package formula

import (
	"context"
	"fmt"
	"regexp"
	"strings"

	libllmjson "haixun-backend/internal/library/llmjson"
	libownpost "haixun-backend/internal/library/ownpost"
	domai "haixun-backend/internal/model/ai/domain/usecase"
)

var pastedFenceRE = regexp.MustCompile("(?s)```(?:json)?\\s*([\\s\\S]*?)```")

type AnalyzePastedInput struct {
	PostText     string
	AuthorName   string
	PersonaBlock string
	LikeCount    int
	ReplyCount   int
}

type PastedAnalysis struct {
	Summary         string   `json:"summary"`
	Wins            []string `json:"wins"`
	Improvements    []string `json:"improvements"`
	Formula         string   `json:"formula"`
	PostTemplate    string   `json:"post_template"`
	HookPattern     string   `json:"hook_pattern"`
	Structure       string   `json:"structure"`
	ReplicationTips []string `json:"replication_tips"`
	Avoid           []string `json:"avoid"`
}

func BuildAnalyzePastedPrompt(in AnalyzePastedInput) (system string, user string) {
	personaBlock := strings.TrimSpace(in.PersonaBlock)
	if personaBlock == "" {
		personaBlock = "（未指定人設，請依貼文本身語氣分析）"
	}
	postText := strings.TrimSpace(in.PostText)
	if postText == "" {
		postText = "（貼文內容未提供）"
	}
	author := strings.TrimSpace(in.AuthorName)
	if author == "" {
		author = "匿名"
	}

	system = strings.TrimSpace(`
你是 Threads / Instagram 貼文結構分析師。任務是拆解「外部貼文」哪些地方可借鏡，再說明如何用指定人設的語言指紋重新說一次；不要產生會讓文案機械的填空模板。

規則：
- 用台灣繁體中文。
- formula：整理可借鏡的敘事/資訊推進方式，但要提醒不可照搬句型。
- post_template：不要寫填空骨架；改寫成「此人設可採用的鬆結構與注意事項」。
- replication_tips：重點放在如何換成人設語言，包括段落節奏、標點換行、知識轉譯與 CTA。
- 只輸出一個 JSON 物件，不要 markdown，欄位：
  summary, wins, improvements, formula, post_template, hook_pattern, structure, replication_tips, avoid
- formula / structure / hook_pattern 必須是字串，不要用陣列或巢狀物件
- wins / improvements / replication_tips / avoid 各 2～5 點字串陣列。`)

	var b strings.Builder
	b.WriteString("【人設脈絡】\n")
	b.WriteString(personaBlock)
	b.WriteString("\n\n【貼文】\n作者：")
	b.WriteString(author)
	if in.LikeCount > 0 || in.ReplyCount > 0 {
		b.WriteString(fmt.Sprintf(" · %d 讚 · %d 留言", in.LikeCount, in.ReplyCount))
	}
	b.WriteString("\n")
	b.WriteString(postText)
	b.WriteString("\n\n請分析爆款結構並輸出 JSON。")
	user = b.String()
	return system, user
}

func AnalyzePasted(ctx context.Context, ai domai.UseCase, req domai.GenerateRequest, in AnalyzePastedInput) (*PastedAnalysis, error) {
	system, user := BuildAnalyzePastedPrompt(in)
	temp := 0.65
	req.System = system
	req.Messages = []domai.Message{{Role: "user", Content: user}}
	req.Temperature = &temp
	out, err := ai.GenerateText(ctx, req)
	if err != nil {
		return nil, err
	}
	return ParsePastedAnalysis(out.Text)
}

func ParsePastedAnalysis(raw string) (*PastedAnalysis, error) {
	payload, err := extractPastedJSON(raw)
	if err != nil {
		return nil, err
	}
	var flex map[string]any
	if err := libllmjson.Unmarshal(payload, &flex); err != nil {
		return nil, fmt.Errorf("parse pasted formula json: %w", err)
	}
	review := pastedAnalysisFromMap(flex)
	if review.Summary == "" && review.Formula == "" && review.PostTemplate == "" {
		return nil, fmt.Errorf("AI 未回傳有效公式內容")
	}
	return review, nil
}

func FromOwnPostReview(review *libownpost.PostFormulaReview) *PastedAnalysis {
	if review == nil {
		return nil
	}
	return &PastedAnalysis{
		Summary:         review.Summary,
		Wins:            review.Wins,
		Improvements:    review.Improvements,
		Formula:         review.Formula,
		PostTemplate:    review.PostTemplate,
		HookPattern:     review.HookPattern,
		Structure:       review.Structure,
		ReplicationTips: review.ReplicationTips,
		Avoid:           review.Avoid,
	}
}

func FromViralAnalysis(hook, structure, emotion, strategy string, takeaways []string) *PastedAnalysis {
	summary := strings.TrimSpace(emotion)
	if summary == "" {
		summary = "爆款結構分析"
	}
	formula := strings.TrimSpace(strategy)
	if structure != "" {
		if formula != "" {
			formula = structure + " → " + formula
		} else {
			formula = structure
		}
	}
	template := ""
	if hook != "" && structure != "" {
		template = "[" + hook + "] → [" + structure + "] → [你的觀點] → [互動收尾]"
	}
	return &PastedAnalysis{
		Summary:         summary,
		Wins:            takeaways,
		Formula:         formula,
		PostTemplate:    template,
		HookPattern:     hook,
		Structure:       structure,
		ReplicationTips: takeaways,
	}
}

func extractPastedJSON(raw string) ([]byte, error) {
	raw = strings.TrimSpace(raw)
	if m := pastedFenceRE.FindStringSubmatch(raw); len(m) == 2 {
		raw = strings.TrimSpace(m[1])
	}
	start := strings.Index(raw, "{")
	end := strings.LastIndex(raw, "}")
	if start < 0 || end <= start {
		return nil, fmt.Errorf("formula output missing json object")
	}
	return []byte(raw[start : end+1]), nil
}
