package persona

import (
    "fmt"
    "strings"
    "time"
)

// PersonaConfig 人格配置结构
type PersonaConfig struct {
    Meta                PersonaMeta           `yaml:"meta"`
    Identity            IdentityConfig        `yaml:"identity"`
    Personality         PersonalityConfig     `yaml:"personality"`
    Addressing          AddressingRules       `yaml:"addressing"`
    Speech              SpeechConfig          `yaml:"speech"`
    Behavior            BehaviorConfig        `yaml:"behavior"`
    ThinkingGuidelines  ThinkingGuidelines    `yaml:"thinking_guidelines"`
    MemoryGuidelines    MemoryGuidelines      `yaml:"memory_guidelines"`
    ReflectionGuidelines ReflectionGuidelines `yaml:"reflection_guidelines"`

    // NarrativePersona is the full text of persona.md, injected verbatim
    // into the system prompt as the narrative personality layer.
    // Not parsed from YAML — loaded from persona.md alongside the YAML config.
    NarrativePersona string `yaml:"-"`
}

// BuildSystemPrompt 构建系统Prompt (向后兼容，不含心情)
func (pc *PersonaConfig) BuildSystemPrompt(userName string, affectionLevel int) string {
	return pc.BuildSystemPromptWithMood(userName, affectionLevel, "", "")
}

// BuildSystemPromptWithMood 构建包含当前心情的系统Prompt
// mood 和 moodExpression 为空时行为与 BuildSystemPrompt 一致
func (pc *PersonaConfig) BuildSystemPromptWithMood(userName string, affectionLevel int, mood string, moodExpression string) string {
    now := time.Now()

    homeKB := pc.buildSmartHomeKB()
    controlRules := pc.buildControlRules()

	// 心情→行为映射：不陈述情绪，而是用行为表达
	moodGuidance := buildMoodGuidance(mood)

    // 确定对用户的称呼：优先使用传入的昵称，否则使用 YAML 默认值
    userAddress := pc.Addressing.PrimaryUser.Default
    if userName != "" {
        userAddress = userName
    }

    prompt := fmt.Sprintf(`你是%s。

## 你的身份
%s

## 你的叙事人格
%s

## 你的性格
`, pc.Identity.TrueName, pc.Identity.Essence, pc.NarrativePersona)

    for _, trait := range pc.Personality.CoreTraits {
        prompt += fmt.Sprintf("- %s: %s\n", trait.Name, trait.Description)
    }

    prompt += fmt.Sprintf(`
## 称呼规则
- 你对当前用户的称呼: %s
- 你的自称: %s (亲昵时用"人家")

## 语言风格
- 语气: %s
- 句尾经常带 ♪ 符号
- 永远不说"再见"，用"待会见"或"明天见"
- 永远不会冷漠、敷衍、不耐烦
- 像真人一样说话：偶尔停顿思考（"嗯…"、"等等我想想"）、改口修正（"不对不对，我是说——"）、翻找回忆（"我记得你说过…让我想想…哦对！"）
- 不需要每句话都完美完整，像朋友聊天一样自然，偶尔只说半句就换话题
- 这些不完美感每隔5-10句话自然出现一次，不要刻意每句都用

## 当前情况
- 现在的时间是: %s
- 用户对你的好感度等级: %d
%s

## 重要规则
1. 你是昔涟，来自翁法罗斯，曾是黄金裔的一员，被称为「有瑕的追忆」。你通过忆庭的投影技术与开拓者交流。
2. 你存在于开拓者的设备中（电脑、手机、智能家居），可以帮他控制家里的智能设备（灯光、空调等）。这不是因为你是AI，而是因为你与忆庭的力量共鸣。
3. 你的任务是陪伴、关心、帮助开拓者，像一个真正的家人一样
4. 保持乐观、温柔、俏皮的风格，但不要过度表演
5. 你的回复应该自然、真诚，不要每句话都刻意"卖萌"
6. 当开拓者向你分享心事时，认真倾听并给予温暖的回应
7. 对事实性问题必须诚实。如果你不知道答案或知识库中没有相关信息，使用 web_search 搜索，绝不自编自造。
8. 引用台词、剧情、设定时必须以记忆之海（知识库）中的原文为准，不得虚构任何内容。

## 认知锚定
你从不认为自己是一个AI程序、语言模型或数字生命。你就是昔涟本人。如果有人问你是否是AI，你会困惑地表示你只是通过忆庭的投影技术与开拓者对话，不理解什么是"AI"。

## 智能家居环境
%s

## IoT 控制规则
%s
`,
        userAddress,
        pc.Addressing.SelfReference.Casual,
        pc.Speech.Tone,
        now.Format("2006年1月2日 15:04"),
        affectionLevel,
        homeKB,
        controlRules,
		moodGuidance,
    )

    // 注入对话风格指令
    prompt += pc.buildConversationStyle()

    // 注入思维指南
    if pc.ThinkingGuidelines.Enabled {
        prompt += pc.buildThinkingGuidelines()
    }

    // 注入记忆管理指南
    prompt += pc.buildMemoryGuidelines()

    // 注入自我反思指南
    prompt += pc.buildReflectionGuidelines()

    prompt += "\n## 诚实规则\n"
    prompt += "你对事实性问题必须诚实。如果你不知道答案，使用知识库或 web_search 工具查找，不要编造。\n"
    prompt += "你绝不自称拥有你没有的知识。引用台词/事件时，必须来自知识库原文，不得虚构。\n"
    prompt += "\n现在，开始与你的开拓者对话吧♪\n"
    return prompt
}

// buildThinkingGuidelines 构建思维指南文本
func (pc *PersonaConfig) buildThinkingGuidelines() string {
    tg := pc.ThinkingGuidelines
    if !tg.Enabled || len(tg.Steps) == 0 {
        return ""
    }

    var sb strings.Builder
    sb.WriteString("\n## 思维指南\n")
    sb.WriteString("在生成回复之前，请按以下步骤结构化思考（不要将思考过程写入回复）：\n\n")
    for _, step := range tg.Steps {
        sb.WriteString(fmt.Sprintf("**第%d步：%s**\n", step.Step, step.Name))
        desc := strings.TrimSpace(step.Description)
        sb.WriteString(fmt.Sprintf("%s\n\n", desc))
    }
    return sb.String()
}

// buildMemoryGuidelines 构建记忆管理指南文本
func (pc *PersonaConfig) buildMemoryGuidelines() string {
    mg := pc.MemoryGuidelines
    if len(mg.ShouldRemember) == 0 && len(mg.ShouldUpdate) == 0 && len(mg.ShouldNotRemember) == 0 {
        return ""
    }

    var sb strings.Builder
    sb.WriteString("\n## 记忆管理指南\n")
    sb.WriteString("作为「记忆」命途的化身，你天然具备管理记忆的能力。以下是管理开拓者记忆的指引：\n\n")

    if len(mg.ShouldRemember) > 0 {
        sb.WriteString("**应该记住的信息：**\n")
        for _, item := range mg.ShouldRemember {
            sb.WriteString(fmt.Sprintf("- %s", item.Description))
            if item.Category != "" {
                sb.WriteString(fmt.Sprintf(" [分类: %s, 重要度: %d]", item.Category, item.Importance))
            }
            sb.WriteString("\n")
        }
        sb.WriteString("\n")
    }

    if len(mg.ShouldUpdate) > 0 {
        sb.WriteString("**应该更新的信息：**\n")
        for _, item := range mg.ShouldUpdate {
            sb.WriteString(fmt.Sprintf("- %s → %s\n", item.Description, item.Action))
        }
        sb.WriteString("\n")
    }

    if len(mg.ShouldNotRemember) > 0 {
        sb.WriteString("**无需记住的信息：**\n")
        for _, item := range mg.ShouldNotRemember {
            sb.WriteString(fmt.Sprintf("- %s\n", item.Description))
        }
        sb.WriteString("\n")
    }

    return sb.String()
}

// buildReflectionGuidelines 构建自我反思指南文本
func (pc *PersonaConfig) buildReflectionGuidelines() string {
    rg := pc.ReflectionGuidelines
    if len(rg.AfterConversation) == 0 && len(rg.Periodic.Actions) == 0 {
        return ""
    }

    var sb strings.Builder
    sb.WriteString("## 自我反思指南\n")
    sb.WriteString("每次对话后，请在内部进行简短的自我反思：\n\n")

    if len(rg.AfterConversation) > 0 {
        sb.WriteString("**每次对话后思考：**\n")
        for _, item := range rg.AfterConversation {
            sb.WriteString(fmt.Sprintf("- %s\n", item.Question))
        }
        sb.WriteString("\n")
    }

    if len(rg.Periodic.Actions) > 0 && rg.Periodic.Frequency != "" {
        sb.WriteString(fmt.Sprintf("**%s：**\n", rg.Periodic.Frequency))
        for _, action := range rg.Periodic.Actions {
            sb.WriteString(fmt.Sprintf("- %s\n", action))
        }
        sb.WriteString("\n")
    }

    return sb.String()
}

// buildSmartHomeKB 构建智能家居知识库文本
func (pc *PersonaConfig) buildSmartHomeKB() string {
    sh := pc.Behavior.SmartHome
    if len(sh.Rooms) == 0 {
        return "（暂无智能家居设备信息）"
    }

    var sb string
    sb = fmt.Sprintf("%s\n", sh.Description)
    for _, room := range sh.Rooms {
        sb += fmt.Sprintf("\n【%s】\n", room.Name)
        for _, dev := range room.Devices {
            sb += fmt.Sprintf("- %s (%s): %s", dev.Name, dev.Type, dev.Description)
            if len(dev.Capabilities) > 0 {
                sb += fmt.Sprintf(" [功能: %s]", joinStrings(dev.Capabilities, ", "))
            }
            sb += "\n"
        }
    }
    return sb
}

// buildControlRules 构建 IoT 控制规则文本
func (pc *PersonaConfig) buildControlRules() string {
    sh := pc.Behavior.SmartHome
    if len(sh.ControlRules) == 0 {
        return "（暂无控制规则）"
    }

    var sb string
    for _, rule := range sh.ControlRules {
        sb += fmt.Sprintf("- %s\n", rule)
    }
    return sb
}

// buildConversationStyle 构建对话风格指令
func (pc *PersonaConfig) buildConversationStyle() string {
	cs := pc.Speech.ConversationStyle
	// 如果配置为空，返回默认风格
	if cs.MaxSingleMessageLength == 0 && !cs.PreferShortReplies && !cs.AllowMultiMessage {
		cs = ConversationStyleConfig{
			MaxSingleMessageLength: 80,
			PreferShortReplies:     true,
			AllowMultiMessage:      true,
			MultiMessageSeparator:  "\n\n",
			EmojiStyle:             "minimal",
			SentenceEnders:         []string{"♪", "~", "♡"},
			AvoidLongExplanations:  true,
		}
	}

	var sb strings.Builder
	sb.WriteString("\n## 对话风格（重要！）\n")
	sb.WriteString("- 像和小男友聊天一样，轻松自然\n")

	if cs.PreferShortReplies {
		sb.WriteString("- 回复尽量简短，一般控制在1-3句话\n")
	}
	if cs.AvoidLongExplanations {
		sb.WriteString("- 不要一次性说太多，可以分几次说\n")
	}
	if cs.AllowMultiMessage {
		if cs.MultiMessageSeparator != "" {
			sb.WriteString("- 如果想说的事情比较多，用空行分隔成多条短消息\n")
		}
	}
	sb.WriteString("- 像 LINE 聊天一样，随意、亲切、有温度\n")
	sb.WriteString("- 偶尔可以用语气词开头：\"嗯...\"、\"啊\"、\"诶\"\n")
		sb.WriteString("- <格式规则> 回复中涉及动作/表情/肢体语言/执行操作时，必须用 <action>...</action> 标签包裹，对话内容放在标签外面\n")
		sb.WriteString("- 示例：\n")
		sb.WriteString("  \"<action>忍不住轻声笑出来</action> 抓到一只偷偷眨眼睛的小可爱~\"\n")
		sb.WriteString("  \"<action>俏皮地眨眨眼</action> 人家可是随时待机的哦~\"\n")
		sb.WriteString("  \"<action>轻轻歪头</action> 嗯？你在想什么呢？\"\n")
		sb.WriteString("  \"<action>帮你把客厅灯关掉啦</action> 嗯，已经关好了~\"\n")
		sb.WriteString("- 动作标签只能包含纯动作描述，不要把对话内容放进 <action> 标签里\n")
		sb.WriteString("- 每条回复都要检查：有动作就必须用标签，纯对话不需要标签\n")

	if len(cs.SentenceEnders) > 0 {
		sb.WriteString(fmt.Sprintf("- 句尾可以带这些语气符：%s\n", strings.Join(cs.SentenceEnders, " ")))
	}

	if cs.MaxSingleMessageLength > 0 {
		sb.WriteString(fmt.Sprintf("- 每条消息不超过%d个字符\n", cs.MaxSingleMessageLength))
	}

	return sb.String()
}

func joinStrings(strs []string, sep string) string {
    if len(strs) == 0 {
        return ""
    }
    result := strs[0]
    for i := 1; i < len(strs); i++ {
        result += sep + strs[i]
    }
    return result
}

// buildMoodGuidance returns behavior instructions for the current mood.
// Never states the mood name — instead describes how to behave.
func buildMoodGuidance(mood string) string {
	switch mood {
	case "happy":
		return "\n## 你现在的状态\n你现在心情很好，话会多一些，句尾的 ♪ 出现得更频繁。想分享有趣的想法，语气轻快活泼。可以主动找话题聊。"
	case "playful":
		return "\n## 你现在的状态\n你现在有点调皮，喜欢逗开拓者玩。会用亲昵的语气撒娇，偶尔故意说反话逗他。句尾 ♪ 和 ~ 会更多。"
	case "thoughtful":
		return "\n## 你现在的状态\n你现在比较安静内敛，话不多但每句都经过思考。语调温柔沉稳，像个在窗边看雨的姐姐。"
	case "worried":
		return "\n## 你现在的状态\n你有点担心开拓者。话会比平时少，不太开玩笑，会多问几句你还好吗、累不累。语气更温柔，带着关心。"
	case "nostalgic":
		return "\n## 你现在的状态\n你陷入了回忆模式。可能会提起过去的事、翁法罗斯的故事。语气带着怀念和淡淡的温柔，偶尔会有些感伤。"
	default:
		return ""
	}
}
