package job

import (
	"context"
	"fmt"
	"strings"

	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	libviral "haixun-backend/internal/library/viral"
	domai "haixun-backend/internal/model/ai/domain/usecase"
	aiusecase "haixun-backend/internal/model/ai/usecase"
	missionentity "haixun-backend/internal/model/copy_mission/domain/entity"
	missiondomain "haixun-backend/internal/model/copy_mission/domain/usecase"
	jobdom "haixun-backend/internal/model/job/domain/usecase"
	personadomain "haixun-backend/internal/model/persona/domain/usecase"
	placementusecase "haixun-backend/internal/model/placement/usecase"
	threadsaccountdomain "haixun-backend/internal/model/threads_account/domain/usecase"
)

type AnalyzeCopyMissionDeps struct {
	Jobs           jobdom.UseCase
	CopyMission    missiondomain.UseCase
	Persona        personadomain.UseCase
	ThreadsAccount threadsaccountdomain.UseCase
	Placement      placementusecase.UseCase
	AI             aiusecase.UseCase
}

func RegisterAnalyzeCopyMissionHandler(runner *Runner, deps AnalyzeCopyMissionDeps) {
	if runner == nil {
		return
	}
	runner.RegisterStepHandler("copy_mission_map", func(ctx context.Context, step StepContext) error {
		return runAnalyzeCopyMission(ctx, step, deps)
	})
}

func runAnalyzeCopyMission(ctx context.Context, step StepContext, deps AnalyzeCopyMissionDeps) error {
	payload := step.Run.Payload
	tenantID, ownerUID := runActorFromPayload(payload, step.Run)
	personaID := stringField(payload, "persona_id")
	missionID := stringField(payload, "copy_mission_id")
	if tenantID == "" || ownerUID == "" || personaID == "" || missionID == "" {
		return fmt.Errorf("analyze-copy-mission payload missing tenant_id, owner_uid, persona_id, or copy_mission_id")
	}

	mission, err := deps.CopyMission.Get(ctx, tenantID, ownerUID, personaID, missionID)
	if err != nil {
		return err
	}
	persona, err := deps.Persona.Get(ctx, tenantID, ownerUID, personaID)
	if err != nil {
		return err
	}

	updateProgress := func(summary string, percentage int) {
		_ = step.Heartbeat(ctx)
		_, _ = deps.Jobs.UpdateProgress(ctx, jobdom.UpdateProgressRequest{
			JobID:      step.JobID,
			WorkerID:   step.WorkerID,
			Phase:      "copy_mission_map",
			Summary:    summary,
			Percentage: percentage,
		})
	}

	updateProgress("產生拷貝任務研究地圖…", 15)

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

	result, err := deps.AI.GenerateText(ctx, domai.GenerateRequest{
		Provider: providerID,
		Model:    credential.Model,
		Credential: domai.Credential{
			APIKey: credential.APIKey,
		},
		System: libviral.BuildMissionResearchMapSystemPrompt(),
		Messages: []domai.Message{
			{
				Role: "user",
				Content: libviral.BuildMissionResearchMapUserPrompt(libviral.CopyResearchMapInput{
					Label:                  mission.Label,
					SeedQuery:              mission.SeedQuery,
					Brief:                  mission.Brief,
					Persona:                persona.Persona,
					StyleBenchmark:         persona.StyleBenchmark,
					PersonaAudienceSummary: persona.CopyResearchMap.AudienceSummary,
					PersonaContentGoal:     persona.CopyResearchMap.ContentGoal,
					PersonaQuestions:       append([]string(nil), persona.CopyResearchMap.Questions...),
					PersonaPillars:         append([]string(nil), persona.CopyResearchMap.Pillars...),
				}),
			},
		},
	})
	if err != nil {
		return err
	}

	parsed, err := libviral.ParseMissionResearchMapOutput(result.Text)
	if err != nil {
		return app.For(code.AI).SvcThirdParty("拷貝任務研究地圖 LLM 回傳無法解析：" + err.Error())
	}

	entityTags := make([]missionentity.SuggestedTag, 0, len(parsed.SuggestedTags))
	for _, tag := range parsed.SuggestedTags {
		entityTags = append(entityTags, missionentity.SuggestedTag{
			Tag:          tag.Tag,
			Reason:       tag.Reason,
			SearchIntent: tag.SearchIntent,
			SearchType:   tag.SearchType,
		})
	}
	researchMap := missionentity.ResearchMap{
		AudienceSummary: parsed.AudienceSummary,
		ContentGoal:     parsed.ContentGoal,
		Questions:       parsed.Questions,
		Pillars:         parsed.Pillars,
		Exclusions:      parsed.Exclusions,
		BenchmarkNotes:  parsed.BenchmarkNotes,
	}
	entityTags = make([]missionentity.SuggestedTag, 0, len(parsed.SuggestedTags))
	for _, tag := range parsed.SuggestedTags {
		entityTags = append(entityTags, missionentity.SuggestedTag{
			Tag:          tag.Tag,
			Reason:       tag.Reason,
			SearchIntent: tag.SearchIntent,
			SearchType:   tag.SearchType,
		})
	}
	researchMap.SimilarAccounts = nil
	researchMap.SuggestedTags = entityTags
	selected := libviral.PickDefaultSelectedTags(parsed.SuggestedTags)

	mapped := missionentity.StatusMapped
	updateProgress("儲存研究地圖與預設標籤…", 85)
	_, err = deps.CopyMission.Update(ctx, missiondomain.UpdateRequest{
		TenantID:  tenantID,
		OwnerUID:  ownerUID,
		PersonaID: personaID,
		MissionID: missionID,
		Patch: missiondomain.MissionPatch{
			ResearchMap:     &researchMap,
			SelectedTagsSet: true,
			SelectedTags:    selected,
			Status:          &mapped,
		},
	})
	if err != nil {
		return err
	}

	handoff := map[string]any{
		"flow":            "copy",
		"persona_id":      personaID,
		"copy_mission_id": missionID,
		"summary":         fmt.Sprintf("研究地圖就緒，已預選 %d 個搜尋標籤", len(selected)),
		"next_route":      fmt.Sprintf("/matrix/missions/%s", missionID),
	}

	_, err = deps.Jobs.CompleteRun(ctx, jobdom.CompleteRunRequest{
		JobID:    step.JobID,
		WorkerID: step.WorkerID,
		Result: map[string]any{
			"tag_count":      len(entityTags),
			"account_count":  0,
			"selected_count": len(selected),
			"handoff":        handoff,
		},
	})
	return err
}

func copyMissionIDFromPayload(payload map[string]any) string {
	if id := stringField(payload, "copy_mission_id"); id != "" {
		return id
	}
	return strings.TrimSpace(stringField(payload, "mission_id"))
}
