package ownpost

import (
	"context"
	"fmt"
	"regexp"
	"strings"
	"unicode/utf8"

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

type ReplyDraftInput struct {
	AccountName     string
	PersonaBlock    string
	PostText        string
	ReplyText       string
	ReplyToID       string
	ThreadPostText  string
	ParentReplyText string
}

var (
	wrapQuoteRE   = regexp.MustCompile(`^["'「『](.*)["'」』]$`)
	multiBlankRE  = regexp.MustCompile(`\n{3,}`)
	sentenceEndRE = regexp.MustCompile(`([。！？…!?])\s*`)
	aiPhraseRE    = regexp.MustCompile(`(?i)(很高興|感謝您的|希望這對您|作為一個|總而言之|綜上所述|不妨考慮|值得注意)`)
)

func isMentionReplyDraft(in ReplyDraftInput) bool {
	return strings.TrimSpace(in.ThreadPostText) != "" || strings.TrimSpace(in.ParentReplyText) != ""
}

func BuildReplyDraftPrompt(in ReplyDraftInput) (system string, user string) {
	if isMentionReplyDraft(in) {
		return buildMentionReplyDraftPrompt(in)
	}
	accountName := strings.TrimSpace(in.AccountName)
	if accountName == "" {
		accountName = "我"
	}
	postText := strings.TrimSpace(in.PostText)
	if postText == "" {
		postText = "（貼文內容未提供）"
	}
	replyText := strings.TrimSpace(in.ReplyText)
	replyToID := strings.TrimSpace(in.ReplyToID)
	personaBlock := strings.TrimSpace(in.PersonaBlock)
	if personaBlock == "" {
		personaBlock = "（尚未設定人設，請用口語、像真人在 Threads 回留言）"
	}

	system = strings.TrimSpace(`
你是 Threads 貼文作者本人，要在自己貼文底下回留言或接續串文。
請用台灣繁體中文，像真人用手機打字，完全不像 AI 或客服。

硬規則：
1. 人設語氣是最高優先：用字、節奏、距離感、價值觀必須符合【1. 人設】，不得變成通用網友或官方口吻。
2. 只輸出一則回覆正文：不要標題、不要 JSON、不要用引號包裹、不要解釋你怎麼寫。
3. 先讀【2. 我的貼文】掌握語境；若有【3. 要回覆的留言】，要直接回應對方說的內容，不要自說自話。
4. 禁止 AI 腔：不要「很高興／感謝您的／希望這對您有幫助／作為一個…／總而言之／綜上所述」這類句型。
5. 禁止客服業配腔：不要硬推、不要條列式教學、不要一次講太多重點。
6. 排版要像真人留言：2～4 個短段落，每段 1～2 句；段落之間必須換行（用實際換行，不要整段擠在一起）。
7. 可口語、可省略主詞、可用 …、可 0～1 個 emoji；總長度約 40～180 字，最多不超過 280 字。
8. 你是貼文作者本人在回，不要假裝是粉絲或路人。`)

	var b strings.Builder
	b.WriteString("【1. 人設】\n")
	b.WriteString(personaBlock)
	b.WriteString("\n\n帳號名稱：")
	b.WriteString(accountName)
	b.WriteString("\n\n【2. 我的貼文】\n")
	b.WriteString(postText)
	b.WriteString("\n\n【3. 要回覆的留言】\n")
	if replyToID != "" && replyText != "" {
		b.WriteString(replyText)
		b.WriteString("\n\n請依人設語氣，回覆這則留言。")
	} else {
		b.WriteString("（無特定留言，這是接續自己貼文的補充回覆／串文）")
		b.WriteString("\n\n請依人設語氣，寫一則自然接續這篇貼文的留言。")
	}
	user = b.String()
	return system, user
}

func buildMentionReplyDraftPrompt(in ReplyDraftInput) (system string, user string) {
	accountName := strings.TrimSpace(in.AccountName)
	if accountName == "" {
		accountName = "我"
	}
	threadText := strings.TrimSpace(in.ThreadPostText)
	if threadText == "" {
		threadText = strings.TrimSpace(in.PostText)
	}
	if threadText == "" {
		threadText = "（主串貼文內容未提供）"
	}
	parentText := strings.TrimSpace(in.ParentReplyText)
	mentionText := strings.TrimSpace(in.ReplyText)
	if mentionText == "" {
		mentionText = "（對方 @ 你的內容未提供）"
	}
	personaBlock := strings.TrimSpace(in.PersonaBlock)
	if personaBlock == "" {
		personaBlock = "（尚未設定人設，請用口語、像真人在 Threads 回留言）"
	}

	system = strings.TrimSpace(`
你是 Threads 帳號本人，有人在你參與的串文裡 @ 你，你要回覆對方。
請用台灣繁體中文，像真人用手機打字，完全不像 AI 或客服。

硬規則：
1. 人設語氣是最高優先：用字、節奏、距離感必須符合【1. 人設】。
2. 先讀【2. 主串貼文】理解整串在講什麼；若有【3. 上層留言】，要知道留言脈絡。
3. 你的回覆必須直接回應【4. 對方 @ 你的內容】，不要忽略對方 tag 你的那句話。
4. 只輸出一則回覆正文：不要標題、不要 JSON、不要用引號包裹、不要解釋你怎麼寫。
5. 禁止 AI 腔與客服腔；2～4 個短段落，段落間換行；約 40～180 字，最多 280 字。
6. 你是被 @ 的當事人在回，語氣自然、有來有往。`)

	var b strings.Builder
	b.WriteString("【1. 人設】\n")
	b.WriteString(personaBlock)
	b.WriteString("\n\n帳號名稱：")
	b.WriteString(accountName)
	b.WriteString("\n\n【2. 主串貼文】\n")
	b.WriteString(threadText)
	if parentText != "" {
		b.WriteString("\n\n【3. 上層留言】\n")
		b.WriteString(parentText)
	}
	b.WriteString("\n\n【4. 對方 @ 你的內容】\n")
	b.WriteString(mentionText)
	b.WriteString("\n\n請依人設語氣，回覆對方 @ 你的這則內容。")
	return system, b.String()
}

func GenerateReplyDraft(ctx context.Context, ai domai.UseCase, req domai.GenerateRequest, in ReplyDraftInput) (string, error) {
	system, user := BuildReplyDraftPrompt(in)
	temp := 0.9
	req.System = system
	req.Messages = []domai.Message{{Role: "user", Content: user}}
	req.Temperature = &temp
	out, err := ai.GenerateText(ctx, req)
	if err != nil {
		return "", err
	}
	text := NormalizeHumanReply(out.Text)
	if text == "" {
		return "", fmt.Errorf("AI 未回傳回覆草稿")
	}
	return text, nil
}

// NormalizeHumanReply trims AI artifacts and nudges layout toward short mobile-style paragraphs.
func NormalizeHumanReply(raw string) string {
	text := strings.TrimSpace(raw)
	if text == "" {
		return ""
	}
	if m := wrapQuoteRE.FindStringSubmatch(text); len(m) == 2 {
		text = strings.TrimSpace(m[1])
	}
	text = strings.ReplaceAll(text, `\n`, "\n")
	text = multiBlankRE.ReplaceAllString(text, "\n\n")
	text = strings.TrimSpace(text)

	if !strings.Contains(text, "\n") {
		if sentenceCount(text) >= 2 || utf8.RuneCountInString(text) > 72 {
			text = breakLongReply(text)
		}
	}
	if aiPhraseRE.MatchString(text) && !strings.Contains(text, "\n") {
		text = breakLongReply(text)
	}
	return strings.TrimSpace(text)
}

func sentenceCount(text string) int {
	n := 0
	for _, r := range text {
		switch r {
		case '。', '！', '？', '…', '!', '?':
			n++
		}
	}
	return n
}

func breakLongReply(text string) string {
	parts := sentenceEndRE.Split(text, -1)
	seps := sentenceEndRE.FindAllString(text, -1)
	if len(parts) <= 1 {
		return text
	}
	var chunks []string
	var current strings.Builder
	for i, part := range parts {
		part = strings.TrimSpace(part)
		if part == "" {
			continue
		}
		sep := ""
		if i < len(seps) {
			sep = strings.TrimSpace(seps[i])
		}
		segment := part + sep
		if current.Len() == 0 {
			current.WriteString(segment)
			continue
		}
		if utf8.RuneCountInString(current.String())+utf8.RuneCountInString(segment) > 42 {
			chunks = append(chunks, strings.TrimSpace(current.String()))
			current.Reset()
			current.WriteString(segment)
			continue
		}
		current.WriteString(segment)
	}
	if current.Len() > 0 {
		chunks = append(chunks, strings.TrimSpace(current.String()))
	}
	if len(chunks) <= 1 {
		return text
	}
	return strings.Join(chunks, "\n")
}
