import json
from json_repair import repair_json
from typing import Tuple
import time

from src.common.logger import get_logger
from src.config.config import global_config
from src.person_info.person_info import Person, get_memory_content_from_memory, get_weight_from_memory
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
from src.plugin_system import BaseAction, ActionActivationType
from src.plugin_system.apis import llm_api


logger = get_logger("relation")


def init_prompt():
    Prompt(
        """
以下是一些记忆条目的分类：
----------------------
{category_list}
----------------------
每一个分类条目类型代表了你对用户："{person_name}"的印象的一个类别

现在，你有一条对 {person_name} 的新记忆内容：
{memory_point}

请判断该记忆内容是否属于上述分类，请给出分类的名称。
如果不属于上述分类，请输出一个合适的分类名称，对新记忆内容进行概括。要求分类名具有概括性。
注意分类数一般不超过5个
请严格用json格式输出，不要输出任何其他内容：
{{
    "category": "分类名称"
}} """,
        "relation_category",
    )

    Prompt(
        """
以下是有关{category}的现有记忆：
----------------------
{memory_list}
----------------------

现在，你有一条对 {person_name} 的新记忆内容：
{memory_point}

请判断该新记忆内容是否已经存在于现有记忆中，你可以对现有进行进行以下修改：
注意，一般来说记忆内容不超过5个，且记忆文本不应太长

1.新增：当记忆内容不存在于现有记忆，且不存在矛盾，请用json格式输出：
{{
    "new_memory": "需要新增的记忆内容"
}}
2.加深印象：如果这个新记忆已经存在于现有记忆中，在内容上与现有记忆类似，请用json格式输出：
{{
    "memory_id": 1, #请输出你认为需要加深印象的，与新记忆内容类似的，已经存在的记忆的序号
    "integrate_memory": "加深后的记忆内容，合并内容类似的新记忆和旧记忆"
}}
3.整合：如果这个新记忆与现有记忆产生矛盾，请你结合其他记忆进行整合，用json格式输出：
{{
    "memory_id": 1, #请输出你认为需要整合的，与新记忆存在矛盾的，已经存在的记忆的序号
    "integrate_memory": "整合后的记忆内容，合并内容矛盾的新记忆和旧记忆"
}}

现在，请你根据情况选出合适的修改方式，并输出json，不要输出其他内容：
""",
        "relation_category_update",
    )


class BuildRelationAction(BaseAction):
    """关系动作 - 构建关系"""

    activation_type = ActionActivationType.LLM_JUDGE
    parallel_action = True

    # 动作基本信息
    action_name = "build_relation"
    action_description = "了解对于某人的记忆，并添加到你对对方的印象中"

    # 动作参数定义
    action_parameters = {"person_name": "需要了解或记忆的人的名称", "impression": "需要了解的对某人的记忆或印象"}

    # 动作使用场景
    action_require = [
        "了解对于某人的记忆，并添加到你对对方的印象中",
        "对方与有明确提到有关其自身的事件",
        "对方有提到其个人信息，包括喜好，身份，等等",
        "对方希望你记住对方的信息",
    ]

    # 关联类型
    associated_types = ["text"]

    async def execute(self) -> Tuple[bool, str]:
        """执行关系动作"""

        try:
            # 1. 获取构建关系的原因
            impression = self.action_data.get("impression", "")
            logger.info(f"{self.log_prefix} 添加关系印象原因: {self.reasoning}")
            person_name = self.action_data.get("person_name", "")
            # 2. 获取目标用户信息
            person = Person(person_name=person_name)
            if not person.is_known:
                logger.warning(f"{self.log_prefix} 用户 {person_name} 不存在，跳过添加记忆")
                return False, f"用户 {person_name} 不存在，跳过添加记忆"

            person.last_know = time.time()
            person.know_times += 1
            person.sync_to_database()

            category_list = person.get_all_category()
            if not category_list:
                category_list_str = "无分类"
            else:
                category_list_str = "\n".join(category_list)

            prompt = await global_prompt_manager.format_prompt(
                "relation_category",
                category_list=category_list_str,
                memory_point=impression,
                person_name=person.person_name,
            )

            if global_config.debug.show_prompt:
                logger.info(f"{self.log_prefix} 生成的LLM Prompt: {prompt}")
            else:
                logger.debug(f"{self.log_prefix} 生成的LLM Prompt: {prompt}")

            # 5. 调用LLM
            models = llm_api.get_available_models()
            chat_model_config = models.get("utils_small")  # 使用字典访问方式
            if not chat_model_config:
                logger.error(f"{self.log_prefix} 未找到'utils_small'模型配置，无法调用LLM")
                return False, "未找到'utils_small'模型配置"

            success, category, _, _ = await llm_api.generate_with_model(
                prompt, model_config=chat_model_config, request_type="relation.category"
            )

            category_data = json.loads(repair_json(category))
            category = category_data.get("category", "")
            if not category:
                logger.warning(f"{self.log_prefix} LLM未给出分类，跳过添加记忆")
                return False, "LLM未给出分类，跳过添加记忆"

            # 第二部分：更新记忆

            memory_list = person.get_memory_list_by_category(category)
            if not memory_list:
                logger.info(f"{self.log_prefix} {person.person_name} 的  {category}  的记忆为空，进行创建")
                person.memory_points.append(f"{category}:{impression}:1.0")
                person.sync_to_database()

                return True, f"未找到分类为{category}的记忆点，进行添加"

            memory_list_str = ""
            memory_list_id = {}
            for id, memory in enumerate(memory_list, start=1):
                memory_content = get_memory_content_from_memory(memory)
                memory_list_str += f"{id}. {memory_content}\n"
                memory_list_id[id] = memory
            prompt = await global_prompt_manager.format_prompt(
                "relation_category_update",
                category=category,
                memory_list=memory_list_str,
                memory_point=impression,
                person_name=person.person_name,
            )

            if global_config.debug.show_prompt:
                logger.info(f"{self.log_prefix} 生成的LLM Prompt: {prompt}")
            else:
                logger.debug(f"{self.log_prefix} 生成的LLM Prompt: {prompt}")

            chat_model_config = models.get("utils")
            success, update_memory, _, _ = await llm_api.generate_with_model(
                prompt,
                model_config=chat_model_config,  # type: ignore
                request_type="relation.category.update",  # type: ignore
            )

            update_memory_data = json.loads(repair_json(update_memory))
            new_memory = update_memory_data.get("new_memory", "")
            memory_id = update_memory_data.get("memory_id", "")
            integrate_memory = update_memory_data.get("integrate_memory", "")

            if new_memory:
                # 新记忆
                person.memory_points.append(f"{category}:{new_memory}:1.0")
                person.sync_to_database()

                logger.info(f"{self.log_prefix} 为{person.person_name}新增记忆点: {new_memory}")

                return True, f"为{person.person_name}新增记忆点: {new_memory}"
            elif memory_id and integrate_memory:
                # 现存或冲突记忆
                memory = memory_list_id[memory_id]
                memory_content = get_memory_content_from_memory(memory)
                del_count = person.del_memory(category, memory_content)

                if del_count > 0:
                    # logger.info(f"{self.log_prefix} 删除记忆点: {memory_content}")

                    memory_weight = get_weight_from_memory(memory)
                    person.memory_points.append(f"{category}:{integrate_memory}:{memory_weight + 1.0}")
                    person.sync_to_database()

                    logger.info(
                        f"{self.log_prefix} 更新{person.person_name}的记忆点: {memory_content} -> {integrate_memory}"
                    )

                    return True, f"更新{person.person_name}的记忆点: {memory_content} -> {integrate_memory}"

                else:
                    logger.warning(f"{self.log_prefix} 删除记忆点失败: {memory_content}")
                    return False, f"删除{person.person_name}的记忆点失败: {memory_content}"

            return True, "关系动作执行成功"

        except Exception as e:
            logger.error(f"{self.log_prefix} 关系构建动作执行失败: {e}", exc_info=True)
            return False, f"关系动作执行失败: {str(e)}"


# 还缺一个关系的太多遗忘和对应的提取
init_prompt()
