package copy_mission

import (
	"context"
	"fmt"
	"strings"

	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	libmatrix "haixun-backend/internal/library/matrix"
	libprompt "haixun-backend/internal/library/prompt"
	"haixun-backend/internal/library/style8d"
	domai "haixun-backend/internal/model/ai/domain/usecase"
	aiusecase "haixun-backend/internal/model/ai/usecase"
	copydraftentity "haixun-backend/internal/model/copy_draft/domain/entity"
	copydraftdomain "haixun-backend/internal/model/copy_draft/domain/usecase"
	missionentity "haixun-backend/internal/model/copy_mission/domain/entity"
	missiondomain "haixun-backend/internal/model/copy_mission/domain/usecase"
	scanpostdomain "haixun-backend/internal/model/scan_post/domain/usecase"
	"haixun-backend/internal/svc"
	"haixun-backend/internal/types"
)

type GenerateCopyMissionMatrixLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGenerateCopyMissionMatrixLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GenerateCopyMissionMatrixLogic {
	return &GenerateCopyMissionMatrixLogic{ctx: ctx, svcCtx: svcCtx}
}

func (l *GenerateCopyMissionMatrixLogic) GenerateCopyMissionMatrix(
	req *types.GenerateCopyMissionMatrixHandlerReq,
) (*types.GenerateCopyMissionMatrixData, error) {
	tenantID, uid, err := actorFrom(l.ctx)
	if err != nil {
		return nil, err
	}
	personaID := strings.TrimSpace(req.PersonaID)
	missionID := strings.TrimSpace(req.ID)
	mission, err := l.svcCtx.CopyMission.Get(l.ctx, tenantID, uid, personaID, missionID)
	if err != nil {
		return nil, err
	}
	if mission.Status != string(missionentity.StatusScanned) &&
		mission.Status != string(missionentity.StatusDrafted) {
		return nil, app.For(code.Persona).ResInvalidState("請先完成海巡再產出內容矩陣")
	}
	if len(mission.SelectedTags) == 0 {
		return nil, app.For(code.Persona).InputMissingRequired("請先選擇海巡標籤")
	}

	persona, err := l.svcCtx.Persona.Get(l.ctx, tenantID, uid, personaID)
	if err != nil {
		return nil, err
	}
	if !style8d.HasReady8D(persona.Persona, persona.StyleProfile) {
		return nil, app.For(code.Persona).InputMissingRequired("請先完成人設 8D 對標分析")
	}
	personaBlock := style8d.ResolvePersonaBlock(persona.Persona, persona.StyleProfile, persona.Brief)

	count := req.Count
	if count <= 0 {
		count = 5
	}
	if count > 12 {
		count = 12
	}

	posts, err := l.svcCtx.ScanPost.ListForPersona(l.ctx, scanpostdomain.PersonaListRequest{
		TenantID:      tenantID,
		OwnerUID:      uid,
		PersonaID:     personaID,
		CopyMissionID: missionID,
		Limit:         12,
	})
	if err != nil {
		return nil, err
	}
	samples := matrixSamplesFromScanPosts(posts)
	researchBlock := libmatrix.FormatCopyResearchMapBlock(
		mission.ResearchMap.AudienceSummary,
		mission.ResearchMap.ContentGoal,
		mission.ResearchMap.Questions,
		mission.ResearchMap.Pillars,
		mission.ResearchMap.Exclusions,
	)
	userPrompt, err := libmatrix.BuildCopyUserPrompt(libmatrix.CopyGenerateInput{
		Count:        count,
		TopicLabel:   mission.Label,
		TopicBrief:   mission.Brief,
		ResearchMap:  researchBlock,
		SelectedTags: mission.SelectedTags,
		ViralSamples: samples,
		PersonaBlock: personaBlock,
	})
	if err != nil {
		return nil, app.For(code.AI).SysInternal("matrix user prompt load failed")
	}
	systemPrompt, err := libprompt.MatrixCopySystem()
	if err != nil {
		return nil, app.For(code.AI).SysInternal("matrix system prompt load failed")
	}
	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())
	}

	createReqs := make([]copydraftdomain.CreateRequest, 0, len(parsed.Rows))
	for _, row := range parsed.Rows {
		createReqs = append(createReqs, copydraftdomain.CreateRequest{
			CopyMissionID:  missionID,
			DraftType:      copydraftentity.DraftTypeMatrix,
			SortOrder:      row.SortOrder,
			Text:           row.Text,
			Angle:          row.Angle,
			Hook:           row.Hook,
			Rationale:      row.Rationale,
			ReferenceNotes: row.ReferenceNotes,
			Sources:        row.SourcePermalinks,
		})
	}
	saved, err := l.svcCtx.CopyDraft.ReplaceMissionMatrix(l.ctx, tenantID, uid, personaID, missionID, createReqs)
	if err != nil {
		return nil, err
	}

	drafted := missionentity.StatusDrafted
	_, _ = l.svcCtx.CopyMission.Update(l.ctx, missiondomain.UpdateRequest{
		TenantID:  tenantID,
		OwnerUID:  uid,
		PersonaID: personaID,
		MissionID: missionID,
		Patch: missiondomain.MissionPatch{
			Status: &drafted,
		},
	})

	drafts := make([]types.CopyDraftData, 0, len(saved))
	for _, item := range saved {
		drafts = append(drafts, toCopyDraftData(item))
	}
	return &types.GenerateCopyMissionMatrixData{
		Drafts:  drafts,
		Message: fmt.Sprintf("已產出 %d 篇矩陣草稿", len(drafts)),
	}, nil
}

func matrixSamplesFromScanPosts(posts []scanpostdomain.ScanPostSummary) string {
	samples := make([]libmatrix.ViralPostSample, 0, len(posts))
	for _, post := range posts {
		replies := make([]libmatrix.ViralReplySample, 0, len(post.Replies))
		for _, reply := range post.Replies {
			replies = append(replies, libmatrix.ViralReplySample{
				Author: reply.Author,
				Text:   reply.Text,
			})
		}
		samples = append(samples, libmatrix.ViralPostSample{
			Author:    post.Author,
			LikeCount: post.LikeCount,
			SearchTag: post.SearchTag,
			Text:      post.Text,
			Replies:   replies,
		})
	}
	return libmatrix.FormatViralSamples(samples)
}
