"""
Roneia Client - 客户端配置

超级简化的配置文件，只需要最基本的连接信息。
"""

import os
import platform
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional

import yaml


@dataclass
class ServerConnection:
    """服务器连接配置"""
    url: str = "ws://localhost:8765/ws"
    """服务器 WebSocket URL"""

    token: str = ""
    """认证令牌"""

    reconnect_interval: int = 5
    """重连间隔（秒）"""

    max_reconnect_attempts: int = -1  # -1 表示无限重连
    """最大重连次数"""

    heartbeat_interval: int = 30
    """心跳间隔（秒）"""


@dataclass
class PermissionSettings:
    """权限设置"""
    auto_grant: List[str] = field(default_factory=list)
    """自动授权的权限列表"""

    always_ask: bool = False
    """是否总是询问（即使在 auto_grant 中）"""

    use_gui: bool = True
    """是否使用 GUI 弹窗（否则使用终端）"""


@dataclass
class SkillSettings:
    """Skill 设置"""
    directory: str = "./skills"
    """本地 Skill 目录"""

    enabled: List[str] = field(default_factory=list)
    """启用的 Skill 列表（空列表表示启用所有发现的 Skill）"""

    disabled: List[str] = field(default_factory=list)
    """禁用的 Skill 列表"""


@dataclass
class UISettings:
    """UI 设置"""
    enable_tray: bool = True
    """是否启用系统托盘"""

    enable_hotkeys: bool = True
    """是否启用全局快捷键"""

    hotkey_text_input: str = "ctrl+alt+i"
    """文本输入快捷键"""

    hotkey_voice_input: str = "ctrl+alt+v"
    """语音输入快捷键"""


@dataclass
class VoiceConfig:
    """语音功能配置（可覆盖 Server 下发配置）"""
    enabled: bool = True
    """是否启用语音功能"""

    stt_model: str = ""
    """Whisper 模型大小（空表示使用 Server 配置）"""

    stt_device: str = ""
    """STT 设备（空表示使用 Server 配置）"""

    stt_compute_type: str = ""
    """STT 计算类型（空表示使用 Server 配置）"""

    language: str = ""
    """语音识别语言（空表示使用 Server 配置）"""

    tts_voice: str = ""
    """TTS 语音角色（空表示使用 Server 配置）"""

    tts_rate: str = ""
    """TTS 语速（空表示使用 Server 配置）"""

    tts_pitch: str = ""
    """TTS 音调（空表示使用 Server 配置）"""

    tts_volume: str = ""
    """TTS 音量（空表示使用 Server 配置）"""

    vad_aggressiveness: int = -1
    """VAD 灵敏度（-1 表示使用 Server 配置）"""

    silence_duration_ms: int = -1
    """静音判定时长（-1 表示使用 Server 配置）"""


@dataclass
class RoneiaClientConfig:
    """完整客户端配置"""
    server: ServerConnection = field(default_factory=ServerConnection)
    permissions: PermissionSettings = field(default_factory=PermissionSettings)
    skills: SkillSettings = field(default_factory=SkillSettings)
    ui: UISettings = field(default_factory=UISettings)
    voice: VoiceConfig = field(default_factory=VoiceConfig)

    @classmethod
    def from_yaml(cls, path: str) -> "RoneiaClientConfig":
        """从 YAML 文件加载配置"""
        config_path = Path(path)
        if not config_path.exists():
            return cls()

        with open(config_path, "r", encoding="utf-8") as f:
            data = yaml.safe_load(f) or {}

        return cls._from_dict(data)

    @classmethod
    def from_env(cls) -> "RoneiaClientConfig":
        """从环境变量加载配置"""
        config = cls()

        # 服务器连接
        config.server.url = os.getenv("RONEIA_SERVER_URL", config.server.url)
        config.server.token = os.getenv("RONEIA_AUTH_TOKEN", config.server.token)

        # Skill 目录
        config.skills.directory = os.getenv("RONEIA_SKILL_DIR", config.skills.directory)

        return config

    @classmethod
    def _from_dict(cls, data: Dict[str, Any]) -> "RoneiaClientConfig":
        """从字典创建配置"""
        config = cls()

        # Server
        if "server" in data:
            srv = data["server"]
            config.server.url = srv.get("url", config.server.url)
            config.server.token = srv.get("token", config.server.token)
            config.server.reconnect_interval = srv.get("reconnect_interval", config.server.reconnect_interval)
            config.server.max_reconnect_attempts = srv.get("max_reconnect_attempts", config.server.max_reconnect_attempts)
            config.server.heartbeat_interval = srv.get("heartbeat_interval", config.server.heartbeat_interval)

        # Permissions
        if "permissions" in data:
            perm = data["permissions"]
            config.permissions.auto_grant = perm.get("auto_grant", config.permissions.auto_grant)
            config.permissions.always_ask = perm.get("always_ask", config.permissions.always_ask)
            config.permissions.use_gui = perm.get("use_gui", config.permissions.use_gui)

        # Skills
        if "skills" in data:
            skl = data["skills"]
            config.skills.directory = skl.get("directory", config.skills.directory)
            config.skills.enabled = skl.get("enabled", config.skills.enabled)
            config.skills.disabled = skl.get("disabled", config.skills.disabled)

        # UI
        if "ui" in data:
            ui = data["ui"]
            config.ui.enable_tray = ui.get("enable_tray", config.ui.enable_tray)
            config.ui.enable_hotkeys = ui.get("enable_hotkeys", config.ui.enable_hotkeys)
            config.ui.hotkey_text_input = ui.get("hotkey_text_input", config.ui.hotkey_text_input)
            config.ui.hotkey_voice_input = ui.get("hotkey_voice_input", config.ui.hotkey_voice_input)

        # Voice
        if "voice" in data:
            v = data["voice"]
            config.voice.enabled = v.get("enabled", config.voice.enabled)
            config.voice.stt_model = v.get("stt_model", config.voice.stt_model)
            config.voice.stt_device = v.get("stt_device", config.voice.stt_device)
            config.voice.stt_compute_type = v.get("stt_compute_type", config.voice.stt_compute_type)
            config.voice.language = v.get("language", config.voice.language)
            config.voice.tts_voice = v.get("tts_voice", config.voice.tts_voice)
            config.voice.tts_rate = v.get("tts_rate", config.voice.tts_rate)
            config.voice.tts_pitch = v.get("tts_pitch", config.voice.tts_pitch)
            config.voice.tts_volume = v.get("tts_volume", config.voice.tts_volume)
            config.voice.vad_aggressiveness = v.get("vad_aggressiveness", config.voice.vad_aggressiveness)
            config.voice.silence_duration_ms = v.get("silence_duration_ms", config.voice.silence_duration_ms)

        return config

    def merge_env(self) -> "RoneiaClientConfig":
        """合并环境变量配置（环境变量优先）"""
        if os.getenv("RONEIA_SERVER_URL"):
            self.server.url = os.getenv("RONEIA_SERVER_URL")
        if os.getenv("RONEIA_AUTH_TOKEN"):
            self.server.token = os.getenv("RONEIA_AUTH_TOKEN")
        if os.getenv("RONEIA_SKILL_DIR"):
            self.skills.directory = os.getenv("RONEIA_SKILL_DIR")
        return self

    def to_yaml(self, path: str) -> None:
        """保存配置到 YAML 文件"""
        data = {
            "server": {
                "url": self.server.url,
                "token": self.server.token,
                "reconnect_interval": self.server.reconnect_interval,
                "max_reconnect_attempts": self.server.max_reconnect_attempts,
                "heartbeat_interval": self.server.heartbeat_interval,
            },
            "permissions": {
                "auto_grant": self.permissions.auto_grant,
                "always_ask": self.permissions.always_ask,
                "use_gui": self.permissions.use_gui,
            },
            "skills": {
                "directory": self.skills.directory,
                "enabled": self.skills.enabled,
                "disabled": self.skills.disabled,
            },
            "ui": {
                "enable_tray": self.ui.enable_tray,
                "enable_hotkeys": self.ui.enable_hotkeys,
                "hotkey_text_input": self.ui.hotkey_text_input,
                "hotkey_voice_input": self.ui.hotkey_voice_input,
            },
        }

        Path(path).parent.mkdir(parents=True, exist_ok=True)
        with open(path, "w", encoding="utf-8") as f:
            yaml.dump(data, f, default_flow_style=False, allow_unicode=True)


def load_client_config(config_path: Optional[str] = None) -> RoneiaClientConfig:
    """
    加载客户端配置

    优先级：环境变量 > 配置文件 > 默认值

    Args:
        config_path: 配置文件路径（可选）

    Returns:
        客户端配置
    """
    if config_path:
        config = RoneiaClientConfig.from_yaml(config_path)
    else:
        # 尝试默认路径
        default_paths = [
            "./config.yaml",
            "./client.yaml",
            "~/.roneia/config.yaml",
        ]
        config = RoneiaClientConfig()
        for path in default_paths:
            expanded_path = os.path.expanduser(path)
            if Path(expanded_path).exists():
                config = RoneiaClientConfig.from_yaml(expanded_path)
                break

    # 合并环境变量
    return config.merge_env()


def merge_voice_config(server_config: Optional[Dict[str, Any]], local_config: "VoiceConfig") -> Dict[str, Any]:
    """
    合并语音配置（本地非空值覆盖 Server 配置）

    Args:
        server_config: Server 下发的语音配置字典
        local_config: 本地 VoiceConfig

    Returns:
        合并后的配置字典
    """
    merged = dict(server_config) if server_config else {
        "enabled": True,
        "stt_model": "large-v3",
        "stt_device": "auto",
        "stt_compute_type": "auto",
        "language": "zh",
        "tts_voice": "zh-CN-XiaoxiaoNeural",
        "tts_rate": "+8%",
        "tts_pitch": "+2Hz",
        "tts_volume": "+0%",
        "vad_aggressiveness": 2,
        "silence_duration_ms": 1500,
    }

    # 本地非空/非默认值覆盖
    if local_config.stt_model:
        merged["stt_model"] = local_config.stt_model
    if local_config.stt_device:
        merged["stt_device"] = local_config.stt_device
    if local_config.stt_compute_type:
        merged["stt_compute_type"] = local_config.stt_compute_type
    if local_config.language:
        merged["language"] = local_config.language
    if local_config.tts_voice:
        merged["tts_voice"] = local_config.tts_voice
    if local_config.tts_rate:
        merged["tts_rate"] = local_config.tts_rate
    if local_config.tts_pitch:
        merged["tts_pitch"] = local_config.tts_pitch
    if local_config.tts_volume:
        merged["tts_volume"] = local_config.tts_volume
    if local_config.vad_aggressiveness >= 0:
        merged["vad_aggressiveness"] = local_config.vad_aggressiveness
    if local_config.silence_duration_ms >= 0:
        merged["silence_duration_ms"] = local_config.silence_duration_ms

    return merged


def get_client_info() -> Dict[str, Any]:
    """
    获取客户端信息

    Returns:
        客户端信息字典
    """
    return {
        "hostname": platform.node(),
        "platform": platform.system(),
        "platform_version": platform.version(),
        "python_version": platform.python_version(),
        "version": "1.0.0",
    }
