package usecase

import (
	"context"
	"strings"
	"time"

	"haixun-backend/internal/library/clock"
	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	libthreads "haixun-backend/internal/library/threadsapi"
	domusecase "haixun-backend/internal/model/threads_account/domain/usecase"
)

const defaultTokenRefreshLeadTime = 7 * 24 * time.Hour

func (u *threadsAccountUseCase) ResolveAccountAPIAccessToken(
	ctx context.Context,
	tenantID, ownerUID, accountID string,
) (string, error) {
	account, err := u.assertOwned(ctx, tenantID, ownerUID, accountID)
	if err != nil {
		return "", err
	}
	secrets, err := u.secretsRepo.FindByAccountID(ctx, account.ID)
	if err != nil {
		return "", err
	}
	if secrets == nil || !isValidAPIToken(secrets) {
		return "", app.For(code.ThreadsAccount).InputMissingRequired("此帳號尚未完成 Threads API 連線或 token 已過期")
	}
	return strings.TrimSpace(secrets.APIAccessToken), nil
}

func (u *threadsAccountUseCase) RefreshAccountAPIAccessToken(
	ctx context.Context,
	tenantID, ownerUID, accountID string,
) (*domusecase.SecretsData, error) {
	token, err := u.ResolveAccountAPIAccessToken(ctx, tenantID, ownerUID, accountID)
	if err != nil {
		return nil, err
	}
	result, err := libthreads.RefreshAccessToken(ctx, token)
	if err != nil {
		return nil, app.For(code.ThreadsAccount).SvcThirdParty("Threads token refresh 失敗").WithCause(err)
	}
	expiresAt := int64(0)
	if result.ExpiresIn > 0 {
		expiresAt = libthreads.NsFromNow(result.ExpiresIn)
	}
	return u.SaveAPIAccessToken(ctx, accountID, result.AccessToken, expiresAt)
}

func (u *threadsAccountUseCase) ListTokenRefreshCandidates(
	ctx context.Context,
	leadTime time.Duration,
) ([]domusecase.TokenRefreshCandidate, error) {
	if leadTime <= 0 {
		leadTime = defaultTokenRefreshLeadTime
	}
	deadline := clock.NowUnixNano() + leadTime.Nanoseconds()
	secretsList, err := u.secretsRepo.ListAPIAccessTokensExpiringBefore(ctx, deadline)
	if err != nil {
		return nil, err
	}
	out := make([]domusecase.TokenRefreshCandidate, 0, len(secretsList))
	for _, secrets := range secretsList {
		if secrets == nil || strings.TrimSpace(secrets.APIAccessToken) == "" {
			continue
		}
		account, err := u.repo.FindByIDGlobal(ctx, secrets.AccountID)
		if err != nil || account == nil {
			continue
		}
		out = append(out, domusecase.TokenRefreshCandidate{
			AccountID: account.ID,
			TenantID:  account.TenantID,
			OwnerUID:  account.OwnerUID,
			ExpiresAt: secrets.APITokenExpiresAt,
		})
	}
	return out, nil
}
