package threads_account

import (
	"context"
	"strings"

	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	liboutreach "haixun-backend/internal/library/outreach"
	libownpost "haixun-backend/internal/library/ownpost"
	domai "haixun-backend/internal/model/ai/domain/usecase"
	aiusecase "haixun-backend/internal/model/ai/usecase"
	"haixun-backend/internal/svc"
	"haixun-backend/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type GenerateOwnPostFormulaLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGenerateOwnPostFormulaLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GenerateOwnPostFormulaLogic {
	return &GenerateOwnPostFormulaLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GenerateOwnPostFormulaLogic) GenerateOwnPostFormula(
	req *types.GenerateOwnPostFormulaHandlerReq,
) (*types.GenerateOwnPostFormulaData, error) {
	tenantID, uid, err := actorFrom(l.ctx)
	if err != nil {
		return nil, err
	}
	if req.MediaID == "" {
		return nil, app.For(code.ThreadsAccount).InputMissingRequired("media_id is required")
	}

	account, err := l.svcCtx.ThreadsAccount.Get(l.ctx, tenantID, uid, req.ID)
	if err != nil {
		return nil, err
	}

	if !req.Force {
		if cached, cerr := l.svcCtx.OwnPostFormula.Get(l.ctx, tenantID, uid, req.ID, req.MediaID); cerr == nil && cached != nil {
			data := toOwnPostFormulaReviewData(cached)
			data.FromCache = true
			return &types.GenerateOwnPostFormulaData{OwnPostFormulaReviewData: data}, nil
		}
	}

	credential, err := l.svcCtx.ThreadsAccount.ResolveMemberAiCredential(l.ctx, tenantID, uid)
	if err != nil {
		return nil, err
	}
	providerID, err := aiusecase.MapWorkerProvider(credential.Provider)
	if err != nil {
		return nil, err
	}

	personaBlock := ""
	if personaID := strings.TrimSpace(req.PersonaID); personaID != "" {
		persona, perr := l.svcCtx.Persona.Get(l.ctx, tenantID, uid, personaID)
		if perr != nil {
			return nil, perr
		}
		personaBlock = liboutreach.FormatVoicePersonaBlock(persona)
	} else if personaID = strings.TrimSpace(account.PersonaID); personaID != "" {
		persona, perr := l.svcCtx.Persona.Get(l.ctx, tenantID, uid, personaID)
		if perr == nil {
			personaBlock = liboutreach.FormatVoicePersonaBlock(persona)
		}
	}

	accountName := account.DisplayName
	if accountName == "" {
		accountName = account.Username
	}

	review, err := libownpost.GeneratePostFormula(l.ctx, l.svcCtx.AI, domai.GenerateRequest{
		Provider: providerID,
		Model:    credential.Model,
		Credential: domai.Credential{
			APIKey: credential.APIKey,
		},
	}, libownpost.PostFormulaInput{
		AccountName:  accountName,
		PersonaBlock: personaBlock,
		PostText:     req.PostText,
		TopicTag:     req.TopicTag,
		MediaType:    req.MediaType,
		LikeCount:    req.LikeCount,
		ReplyCount:   req.ReplyCount,
		Views:        req.Views,
		RepostCount:  req.RepostCount,
		QuoteCount:   req.QuoteCount,
		Shares:       req.Shares,
		Timestamp:    req.Timestamp,
	})
	if err != nil {
		return nil, app.For(code.AI).SvcThirdParty("AI 貼文覆盤失敗：" + err.Error())
	}
	saved, err := l.svcCtx.OwnPostFormula.SaveGenerated(
		l.ctx,
		tenantID,
		uid,
		req.ID,
		req.MediaID,
		strings.TrimSpace(req.PersonaID),
		req.PostText,
		review,
	)
	if err != nil {
		return nil, err
	}
	data := toOwnPostFormulaReviewData(saved)
	data.FromCache = false
	return &types.GenerateOwnPostFormulaData{OwnPostFormulaReviewData: data}, nil
}
