package viral

import (
	"encoding/json"
	"fmt"
	"strings"
)

// MissionResearchMap is the structured copy-mission research map (single LLM call).
type MissionResearchMap struct {
	AudienceSummary string         `json:"audienceSummary"`
	ContentGoal     string         `json:"contentGoal"`
	Questions       []string       `json:"questions"`
	Pillars         []string       `json:"pillars"`
	Exclusions      []string       `json:"exclusions"`
	SuggestedTags   []SuggestedTag `json:"suggestedTags"`
	BenchmarkNotes  string         `json:"benchmarkNotes"`
}

func BuildMissionResearchMapSystemPrompt() string {
	return strings.TrimSpace(`你是 Threads 拷貝任務的「延伸知識與相似帳號研究顧問」。目標：把使用者的完整意圖延伸成可產文的知識地圖，並提供適合人工參考的相似帳號搜尋方向；不要把題目壓扁成泛泛短詞。

規則：
1. audienceSummary：必填，2～4 句描述「受眾是誰」（年齡／情境／痛點／會在 Threads 搜什麼），不要只寫人設本人
2. 必須保留使用者原始題目的核心主詞、情境與目的。例如「備孕男生要吃什麼保健品」不可簡化成「老公吃什麼」
3. contentGoal：用延伸知識與人設產出可發的 Threads 內容；爆款貼文只作為可選參考，不是必經來源
4. pillars：延伸知識支柱，至少 4 個；**必須是字串陣列**，每項要能支撐一篇內容，例如營養素、檢查、生活習慣、常見迷思
5. questions：受眾會搜尋或想問的完整問題，5+ 個；字串陣列，需保留主詞與情境
6. exclusions：不要寫的內容，至少 4 個；包含過度醫療承諾、偏方、恐嚇、與題目無關的家庭日常
7. suggestedTags：6～8 個「搜尋查詢」，不是短 hashtag
   - 每個含 tag, reason, searchIntent（痛點|知識|經驗|對比|工具|帳號）, searchType（查詢|情境|帳號）
   - tag 6～22 字，必須保留核心意圖；可以像真人搜尋句，例如「備孕男生保健品」「精蟲品質吃什麼」「男性備孕葉酸鋅」
   - 不要輸出「老公吃什麼」「多閱讀」這種失去主題的泛詞
8. benchmarkNotes：整理延伸知識重點與人工看相似帳號時的觀察方向；可列 3～5 個重點
9. 繁體中文；只回傳 JSON（含 audienceSummary）`)
}

func BuildMissionResearchMapUserPrompt(in CopyResearchMapInput) string {
	var b strings.Builder
	b.WriteString("【任務名稱】")
	b.WriteString(strings.TrimSpace(in.Label))
	b.WriteString("\n【種子關鍵字／近期熱詞】")
	b.WriteString(strings.TrimSpace(in.SeedQuery))
	b.WriteString("\n【這次想找什麼】\n")
	b.WriteString(strings.TrimSpace(in.Brief))
	if p := strings.TrimSpace(in.Persona); p != "" {
		b.WriteString("\n【我的人設（仿寫時會套用，地圖請對準受眾與話題，不要只寫我自己）】\n")
		b.WriteString(p)
	}
	if bench := strings.TrimSpace(in.StyleBenchmark); bench != "" {
		b.WriteString("\n【長期對標帳號參考】@")
		b.WriteString(strings.TrimPrefix(bench, "@"))
		b.WriteString("\n")
	}
	if aud := strings.TrimSpace(in.PersonaAudienceSummary); aud != "" {
		b.WriteString("\n【人設層級受眾研究（請延伸為本次任務受眾，勿只複製）】\n")
		b.WriteString(aud)
		if goal := strings.TrimSpace(in.PersonaContentGoal); goal != "" {
			b.WriteString("\n內容目標參考：")
			b.WriteString(goal)
		}
		if len(in.PersonaQuestions) > 0 {
			b.WriteString("\n受眾提問參考：")
			b.WriteString(strings.Join(in.PersonaQuestions, "、"))
		}
		if len(in.PersonaPillars) > 0 {
			b.WriteString("\n內容支柱參考：")
			b.WriteString(strings.Join(in.PersonaPillars, "、"))
		}
		b.WriteString("\n")
	}
	b.WriteString("\n請產出拷貝任務研究地圖 JSON。請把 suggestedTags 當成完整搜尋查詢，不要壓成短 hashtag。")
	return b.String()
}

func ParseMissionResearchMapOutput(raw string) (MissionResearchMap, error) {
	payload, err := extractCopyMapJSON(raw)
	if err != nil {
		return MissionResearchMap{}, err
	}
	var root map[string]json.RawMessage
	if err := json.Unmarshal(payload, &root); err != nil {
		return MissionResearchMap{}, fmt.Errorf("parse mission research map: %w", err)
	}
	out := MissionResearchMap{
		AudienceSummary: firstJSONString(root, "audienceSummary", "audience_summary"),
		ContentGoal:     firstJSONString(root, "contentGoal", "content_goal"),
		BenchmarkNotes:  firstJSONString(root, "benchmarkNotes", "benchmark_notes"),
		Questions:       parseFlexibleStringList(pickRawMessage(root, "questions")),
		Pillars:         parseFlexibleStringList(pickRawMessage(root, "pillars")),
		Exclusions:      parseFlexibleStringList(pickRawMessage(root, "exclusions")),
		SuggestedTags:   parseFlexibleSuggestedTags(pickRawMessage(root, "suggestedTags", "suggested_tags")),
	}
	if strings.TrimSpace(out.AudienceSummary) == "" {
		return MissionResearchMap{}, fmt.Errorf("mission research map missing audienceSummary")
	}
	if len(out.SuggestedTags) < 4 {
		return MissionResearchMap{}, fmt.Errorf("mission research map needs at least 4 suggested tags")
	}
	return out, nil
}

func cleanSuggestedTags(tags []SuggestedTag) []SuggestedTag {
	out := []SuggestedTag{}
	seen := map[string]struct{}{}
	for _, item := range tags {
		tag := strings.TrimSpace(item.Tag)
		if tag == "" {
			continue
		}
		if _, ok := seen[tag]; ok {
			continue
		}
		seen[tag] = struct{}{}
		out = append(out, SuggestedTag{
			Tag:          tag,
			Reason:       strings.TrimSpace(item.Reason),
			SearchIntent: strings.TrimSpace(item.SearchIntent),
			SearchType:   strings.TrimSpace(item.SearchType),
		})
	}
	return out
}

func ToEntityMissionResearchMap(m MissionResearchMap) map[string]any {
	tags := make([]map[string]any, 0, len(m.SuggestedTags))
	for _, item := range m.SuggestedTags {
		tags = append(tags, map[string]any{
			"tag":           item.Tag,
			"reason":        item.Reason,
			"search_intent": item.SearchIntent,
			"search_type":   item.SearchType,
		})
	}
	return map[string]any{
		"audience_summary": m.AudienceSummary,
		"content_goal":     m.ContentGoal,
		"questions":        m.Questions,
		"pillars":          m.Pillars,
		"exclusions":       m.Exclusions,
		"suggested_tags":   tags,
		"benchmark_notes":  m.BenchmarkNotes,
	}
}
