package ownpost

import (
	"context"
	"encoding/json"
	"fmt"
	"regexp"
	"strings"

	domai "haixun-backend/internal/model/ai/domain/usecase"
)

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

type PostFormulaInput struct {
	AccountName  string
	PersonaBlock string
	PostText     string
	TopicTag     string
	MediaType    string
	LikeCount    int
	ReplyCount   int
	Views        int
	RepostCount  int
	QuoteCount   int
	Shares       int
	Timestamp    string
}

type PostFormulaReview 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 BuildPostFormulaPrompt(in PostFormulaInput) (system string, user string) {
	personaBlock := strings.TrimSpace(in.PersonaBlock)
	if personaBlock == "" {
		personaBlock = "（未指定人設，請依貼文本身語氣分析）"
	}
	postText := strings.TrimSpace(in.PostText)
	if postText == "" {
		postText = "（貼文內容未提供）"
	}

	system = strings.TrimSpace(`
你是 Threads 內容策略教練。任務是針對「已發布的單篇貼文」做誠實覆盤：好的要提炼成可複製公式，壞的要指出問題並給具體改善做法。不要重寫整篇貼文。

規則：
- 用台灣繁體中文。
- 必須同時寫優點與缺點；依成效數據判斷，成效普通或偏差時更要直言問題。
- 分析要具體、可執行，禁止空泛稱讚或空泛批評。
- formula：把「做對的部分」整理成步驟化公式（例：Hook→情境→轉折→觀點→收尾/互動）。
- post_template：依 formula 產出可複製的發文骨架，用 [括號] 標示可替換欄位，讓使用者下次填空就能產文。
- improvements：每點格式固定為「問題：…｜改善：…」，改善必須是可立刻執行的動作（改哪一句、加什麼、刪什麼、換什麼角度）。
- 只輸出一個 JSON 物件，不要 markdown，欄位：
  summary, wins, improvements, formula, post_template, hook_pattern, structure, replication_tips, avoid
- wins / improvements / replication_tips / avoid 各 2～5 點字串陣列。`)

	var b strings.Builder
	b.WriteString("【1. 人設】\n")
	b.WriteString(personaBlock)
	b.WriteString("\n\n帳號：")
	b.WriteString(strings.TrimSpace(in.AccountName))
	b.WriteString("\n\n【2. 貼文內容】\n")
	b.WriteString(postText)
	if tag := strings.TrimSpace(in.TopicTag); tag != "" {
		b.WriteString("\n話題標籤：#")
		b.WriteString(tag)
	}
	if mt := strings.TrimSpace(in.MediaType); mt != "" {
		b.WriteString("\n媒體類型：")
		b.WriteString(mt)
	}
	if ts := strings.TrimSpace(in.Timestamp); ts != "" {
		b.WriteString("\n發布時間：")
		b.WriteString(ts)
	}
	b.WriteString("\n\n【3. 成效數據】\n")
	b.WriteString(fmt.Sprintf("讚 %d｜回覆 %d｜瀏覽 %d｜轉發 %d｜引用 %d｜分享 %d",
		in.LikeCount, in.ReplyCount, in.Views, in.RepostCount, in.QuoteCount, in.Shares))
	b.WriteString("\n\n請誠實覆盤：做對了什麼、哪裡不好、怎麼改，並把做對的部分整理成下次可複製的公式與發文模板 JSON。")
	user = b.String()
	return system, user
}

func GeneratePostFormula(ctx context.Context, ai domai.UseCase, req domai.GenerateRequest, in PostFormulaInput) (*PostFormulaReview, error) {
	system, user := BuildPostFormulaPrompt(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
	}
	review, err := ParsePostFormulaOutput(out.Text)
	if err != nil {
		return nil, err
	}
	return review, nil
}

func ParsePostFormulaOutput(raw string) (*PostFormulaReview, error) {
	payload, err := extractFormulaJSONObject(raw)
	if err != nil {
		return nil, err
	}
	var review PostFormulaReview
	if err := json.Unmarshal(payload, &review); err != nil {
		return nil, fmt.Errorf("parse post formula json: %w", err)
	}
	review.Summary = strings.TrimSpace(review.Summary)
	review.Formula = strings.TrimSpace(review.Formula)
	review.PostTemplate = strings.TrimSpace(review.PostTemplate)
	review.HookPattern = strings.TrimSpace(review.HookPattern)
	review.Structure = strings.TrimSpace(review.Structure)
	review.Wins = trimStringList(review.Wins)
	review.Improvements = trimStringList(review.Improvements)
	review.ReplicationTips = trimStringList(review.ReplicationTips)
	review.Avoid = trimStringList(review.Avoid)
	if review.Summary == "" && review.Formula == "" && review.PostTemplate == "" {
		return nil, fmt.Errorf("AI 未回傳有效覆盤內容")
	}
	return &review, nil
}

func trimStringList(items []string) []string {
	if len(items) == 0 {
		return nil
	}
	out := make([]string, 0, len(items))
	for _, item := range items {
		item = strings.TrimSpace(item)
		if item != "" {
			out = append(out, item)
		}
	}
	if len(out) == 0 {
		return nil
	}
	return out
}

func extractFormulaJSONObject(raw string) ([]byte, error) {
	raw = strings.TrimSpace(raw)
	if m := formulaFenceRE.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
}
