from dataclasses import dataclass
from typing import Dict, List
import json
from pathlib import Path
import random


@dataclass
class Personality:
    """人格特质类"""

    openness: float  # 开放性
    conscientiousness: float  # 尽责性
    extraversion: float  # 外向性
    agreeableness: float  # 宜人性
    neuroticism: float  # 神经质
    bot_nickname: str  # 机器人昵称
    personality_core: str  # 人格核心特点
    personality_sides: List[str]  # 人格侧面描述

    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, personality_core: str = "", personality_sides: List[str] = None):
        if personality_sides is None:
            personality_sides = []
        self.personality_core = personality_core
        self.personality_sides = personality_sides

    @classmethod
    def get_instance(cls) -> "Personality":
        """获取Personality单例实例

        Returns:
            Personality: 单例实例
        """
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance

    def _init_big_five_personality(self):
        """初始化大五人格特质"""
        # 构建文件路径
        personality_file = Path("data/personality") / f"{self.bot_nickname}_personality.per"

        # 如果文件存在，读取文件
        if personality_file.exists():
            with open(personality_file, "r", encoding="utf-8") as f:
                personality_data = json.load(f)
                self.openness = personality_data.get("openness", 0.5)
                self.conscientiousness = personality_data.get("conscientiousness", 0.5)
                self.extraversion = personality_data.get("extraversion", 0.5)
                self.agreeableness = personality_data.get("agreeableness", 0.5)
                self.neuroticism = personality_data.get("neuroticism", 0.5)
        else:
            # 如果文件不存在，根据personality_core和personality_core来设置大五人格特质
            if "活泼" in self.personality_core or "开朗" in self.personality_sides:
                self.extraversion = 0.8
                self.neuroticism = 0.2
            else:
                self.extraversion = 0.3
                self.neuroticism = 0.5

            if "认真" in self.personality_core or "负责" in self.personality_sides:
                self.conscientiousness = 0.9
            else:
                self.conscientiousness = 0.5

            if "友善" in self.personality_core or "温柔" in self.personality_sides:
                self.agreeableness = 0.9
            else:
                self.agreeableness = 0.5

            if "创新" in self.personality_core or "开放" in self.personality_sides:
                self.openness = 0.8
            else:
                self.openness = 0.5

    @classmethod
    def initialize(cls, bot_nickname: str, personality_core: str, personality_sides: List[str]) -> "Personality":
        """初始化人格特质

        Args:
            bot_nickname: 机器人昵称
            personality_core: 人格核心特点
            personality_sides: 人格侧面描述

        Returns:
            Personality: 初始化后的人格特质实例
        """
        instance = cls.get_instance()
        instance.bot_nickname = bot_nickname
        instance.personality_core = personality_core
        instance.personality_sides = personality_sides
        instance._init_big_five_personality()
        return instance

    def to_dict(self) -> Dict:
        """将人格特质转换为字典格式"""
        return {
            "openness": self.openness,
            "conscientiousness": self.conscientiousness,
            "extraversion": self.extraversion,
            "agreeableness": self.agreeableness,
            "neuroticism": self.neuroticism,
            "bot_nickname": self.bot_nickname,
            "personality_core": self.personality_core,
            "personality_sides": self.personality_sides,
        }

    @classmethod
    def from_dict(cls, data: Dict) -> "Personality":
        """从字典创建人格特质实例"""
        instance = cls.get_instance()
        for key, value in data.items():
            setattr(instance, key, value)
        return instance

    def get_prompt(self, x_person, level):
        # 开始构建prompt
        if x_person == 2:
            prompt_personality = "你"
        elif x_person == 1:
            prompt_personality = "我"
        else:
            prompt_personality = "他"
        # person

        prompt_personality += self.personality_core

        if level == 2:
            personality_sides = self.personality_sides
            random.shuffle(personality_sides)
            prompt_personality += f",{personality_sides[0]}"
        elif level == 3:
            personality_sides = self.personality_sides
            for side in personality_sides:
                prompt_personality += f",{side}"

        prompt_personality += "。"

        return prompt_personality
