// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1

package brand

import (
	"context"
	"strings"

	"haixun-backend/internal/library/clock"
	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	libmatrix "haixun-backend/internal/library/matrix"
	libprompt "haixun-backend/internal/library/prompt"
	domai "haixun-backend/internal/model/ai/domain/usecase"
	aiusecase "haixun-backend/internal/model/ai/usecase"
	cmatrixusecase "haixun-backend/internal/model/content_matrix/domain/usecase"
	scanpostusecase "haixun-backend/internal/model/scan_post/domain/usecase"
	"haixun-backend/internal/svc"
	"haixun-backend/internal/types"

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

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

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

func (l *GenerateBrandContentMatrixLogic) GenerateBrandContentMatrix(req *types.GenerateContentMatrixHandlerReq) (resp *types.ContentMatrixData, err error) {
	tenantID, uid, err := actorFrom(l.ctx)
	if err != nil {
		return nil, err
	}
	count := 5
	if req.Count > 0 {
		count = req.Count
	}
	if count > 10 {
		count = 10
	}

	brand, err := l.svcCtx.Brand.Get(l.ctx, tenantID, uid, req.ID)
	if err != nil {
		return nil, err
	}
	posts, err := l.svcCtx.ScanPost.List(l.ctx, scanpostusecase.ListRequest{
		TenantID:      tenantID,
		OwnerUID:      uid,
		BrandID:       req.ID,
		Recent7dOnly:  true,
		ProductFitMin: 70,
		Limit:         12,
	})
	if err != nil {
		return nil, err
	}
	if len(posts) == 0 {
		return nil, app.For(code.Brand).InputMissingRequired("尚無海巡素材，請先執行雙軌海巡")
	}

	materials := make([]libmatrix.MaterialPost, 0, len(posts))
	topic := ""
	for _, post := range posts {
		if topic == "" {
			topic = post.SearchTag
		}
		materials = append(materials, libmatrix.MaterialPost{
			SearchTag: post.SearchTag,
			Author:    post.Author,
			Text:      post.Text,
			Permalink: post.Permalink,
			Priority:  post.Priority,
		})
	}

	userPrompt, err := libmatrix.BuildUserPrompt(libmatrix.GenerateInput{
		Persona:       brand.Brief,
		TopicLabel:    topic,
		AudienceBrief: brand.TargetAudience,
		ProductBrief:  brand.ProductBrief,
		Posts:         materials,
		Count:         count,
	})
	if err != nil {
		return nil, app.For(code.AI).SysInternal("matrix user prompt load failed")
	}
	systemPrompt, err := libprompt.MatrixPlacementSystem()
	if err != nil {
		return nil, app.For(code.AI).SysInternal("matrix system prompt load failed")
	}
	if strings.TrimSpace(brand.Brief) != "" {
		systemPrompt = strings.TrimSpace(systemPrompt) + "\n\n品牌簡述：\n" + strings.TrimSpace(brand.Brief)
	}

	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
	}
	result, err := l.svcCtx.AI.GenerateText(l.ctx, domai.GenerateRequest{
		Provider: providerID,
		Model:    credential.Model,
		Credential: domai.Credential{
			APIKey: credential.APIKey,
		},
		System: systemPrompt,
		Messages: []domai.Message{
			{Role: "user", Content: userPrompt},
		},
	})
	if err != nil {
		return nil, err
	}
	parsed, err := libmatrix.ParseGenerateOutput(result.Text)
	if err != nil {
		return nil, app.For(code.AI).SvcThirdParty("內容矩陣 LLM 回傳無法解析：" + err.Error())
	}

	rows := make([]cmatrixusecase.Row, 0, len(parsed.Rows))
	for _, row := range parsed.Rows {
		rows = append(rows, cmatrixusecase.Row{
			SortOrder:        row.SortOrder,
			SearchTag:        row.SearchTag,
			Angle:            row.Angle,
			Hook:             row.Hook,
			Text:             row.Text,
			ReferenceNotes:   row.ReferenceNotes,
			SourcePermalinks: row.SourcePermalinks,
			Rationale:        row.Rationale,
		})
	}
	now := clock.NowUnixNano()
	saved, err := l.svcCtx.ContentMatrix.Upsert(l.ctx, cmatrixusecase.UpsertRequest{
		TenantID:    tenantID,
		OwnerUID:    uid,
		BrandID:     req.ID,
		Rows:        rows,
		GeneratedAt: now,
	})
	if err != nil {
		return nil, err
	}
	return toContentMatrixData(saved), nil
}
