package usecase

import (
	"context"
	"strings"
	"time"

	"haixun-backend/internal/library/clock"
	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	libownpost "haixun-backend/internal/library/ownpost"
	"haixun-backend/internal/model/own_post_formula/domain/entity"
	domrepo "haixun-backend/internal/model/own_post_formula/domain/repository"
)

const FormulaCacheTTL = 5 * time.Minute

type UseCase interface {
	Get(ctx context.Context, tenantID, ownerUID, accountID, mediaID string) (*entity.Review, error)
	SaveGenerated(ctx context.Context, tenantID, ownerUID, accountID, mediaID, personaID, postText string, review *libownpost.PostFormulaReview) (*entity.Review, error)
	ListByAccount(ctx context.Context, tenantID, ownerUID, accountID string) ([]entity.Review, error)
	IsFresh(review *entity.Review, now int64) bool
}

func (u *useCase) Get(ctx context.Context, tenantID, ownerUID, accountID, mediaID string) (*entity.Review, error) {
	return u.repo.Get(ctx, tenantID, ownerUID, accountID, mediaID)
}

func (u *useCase) IsFresh(review *entity.Review, now int64) bool {
	if review == nil || review.UpdateAt <= 0 {
		return false
	}
	if now <= 0 {
		now = clock.NowUnixNano()
	}
	return now-review.UpdateAt < int64(FormulaCacheTTL)
}

type useCase struct {
	repo domrepo.Repository
}

func NewUseCase(repo domrepo.Repository) UseCase {
	return &useCase{repo: repo}
}

func (u *useCase) SaveGenerated(
	ctx context.Context,
	tenantID, ownerUID, accountID, mediaID, personaID, postText string,
	review *libownpost.PostFormulaReview,
) (*entity.Review, error) {
	if review == nil {
		return nil, app.For(code.ThreadsAccount).InputMissingRequired("review is required")
	}
	accountID = strings.TrimSpace(accountID)
	mediaID = strings.TrimSpace(mediaID)
	if accountID == "" || mediaID == "" {
		return nil, app.For(code.ThreadsAccount).InputMissingRequired("account_id and media_id are required")
	}
	now := clock.NowUnixNano()
	doc := &entity.Review{
		ID:              entity.ReviewDocID(accountID, mediaID),
		TenantID:        strings.TrimSpace(tenantID),
		OwnerUID:        strings.TrimSpace(ownerUID),
		AccountID:       accountID,
		MediaID:         mediaID,
		PersonaID:       strings.TrimSpace(personaID),
		PostText:        strings.TrimSpace(postText),
		Summary:         review.Summary,
		Wins:            review.Wins,
		Improvements:    review.Improvements,
		Formula:         review.Formula,
		PostTemplate:    review.PostTemplate,
		HookPattern:     review.HookPattern,
		Structure:       review.Structure,
		ReplicationTips: review.ReplicationTips,
		Avoid:           review.Avoid,
		CreateAt:        now,
		UpdateAt:        now,
	}
	if existing, err := u.repo.Get(ctx, tenantID, ownerUID, accountID, mediaID); err == nil && existing != nil {
		doc.CreateAt = existing.CreateAt
	}
	return u.repo.Upsert(ctx, doc)
}

func (u *useCase) ListByAccount(ctx context.Context, tenantID, ownerUID, accountID string) ([]entity.Review, error) {
	accountID = strings.TrimSpace(accountID)
	if accountID == "" {
		return nil, app.For(code.ThreadsAccount).InputMissingRequired("account_id is required")
	}
	return u.repo.ListByAccount(ctx, tenantID, ownerUID, accountID)
}
