"""配置服务 - 支持热重载和动态修改"""

import asyncio
import os
import shutil
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Optional

import yaml
from dotenv import load_dotenv

from ..models.schemas import (
    AIProvider,
    AppSettings,
    ChatConfig,
    ConfigResponse,
    ConfigUpdate,
    Live2DModel,
    PromptTemplate,
)


class ConfigService:
    """配置服务，负责配置文件的读取、写入和热重载"""

    def __init__(self, config_path: str = "config.yaml"):
        self.config_path = Path(config_path)
        self.config_data: Dict[str, Any] = {}
        self._lock = asyncio.Lock()
        self.load_config()

    def load_config(self) -> ConfigResponse:
        """加载配置文件"""
        if not self.config_path.exists():
            raise FileNotFoundError(f"配置文件不存在: {self.config_path}")

        with open(self.config_path, "r", encoding="utf-8") as f:
            self.config_data = yaml.safe_load(f)

        return self.get_config()

    def get_config(self) -> ConfigResponse:
        """获取完整配置"""
        return ConfigResponse(
            version=self.config_data.get("version", "1.0"),
            settings=AppSettings(**self.config_data.get("settings", {})),
            providers={
                k: AIProvider(**v) for k, v in self.config_data.get("providers", {}).items()
            },
            prompts={
                k: PromptTemplate(**v) for k, v in self.config_data.get("prompts", {}).items()
            },
            live2d_models=[
                Live2DModel(**model) for model in self.config_data.get("live2d_models", [])
            ],
            chat=ChatConfig(**self.config_data.get("chat", {})),
        )

    async def update_config(self, update: ConfigUpdate) -> ConfigResponse:
        """更新配置（部分更新）"""
        async with self._lock:
            # 备份原配置
            await self._backup_config()

            # 更新配置数据
            if update.settings:
                self.config_data["settings"] = update.settings.model_dump()

            if update.providers:
                if "providers" not in self.config_data:
                    self.config_data["providers"] = {}
                for key, provider in update.providers.items():
                    self.config_data["providers"][key] = provider.model_dump()

            if update.prompts:
                if "prompts" not in self.config_data:
                    self.config_data["prompts"] = {}
                for key, prompt in update.prompts.items():
                    self.config_data["prompts"][key] = prompt.model_dump()

            if update.live2d_models:
                self.config_data["live2d_models"] = [
                    model.model_dump() for model in update.live2d_models
                ]

            if update.chat:
                self.config_data["chat"] = update.chat.model_dump()

            # 保存到文件
            await self._save_config()

            # 重新加载
            return self.load_config()

    async def _backup_config(self):
        """备份配置文件"""
        if self.config_path.exists():
            backup_dir = self.config_path.parent / "backups"
            backup_dir.mkdir(exist_ok=True)

            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            backup_path = backup_dir / f"config_{timestamp}.yaml"

            shutil.copy2(self.config_path, backup_path)

            # 只保留最近 10 个备份
            backups = sorted(backup_dir.glob("config_*.yaml"))
            if len(backups) > 10:
                for old_backup in backups[:-10]:
                    old_backup.unlink()

    async def _save_config(self):
        """保存配置到文件"""
        with open(self.config_path, "w", encoding="utf-8") as f:
            yaml.safe_dump(
                self.config_data, f, allow_unicode=True, default_flow_style=False, sort_keys=False
            )

    # ========================================================================
    # 供应商管理
    # ========================================================================

    async def get_providers(self) -> Dict[str, AIProvider]:
        """获取所有 AI 供应商"""
        return {k: AIProvider(**v) for k, v in self.config_data.get("providers", {}).items()}

    async def add_or_update_provider(self, provider_id: str, provider: AIProvider) -> AIProvider:
        """添加或更新 AI 供应商"""
        async with self._lock:
            await self._backup_config()

            if "providers" not in self.config_data:
                self.config_data["providers"] = {}

            self.config_data["providers"][provider_id] = provider.model_dump()
            await self._save_config()

            return provider

    async def delete_provider(self, provider_id: str) -> bool:
        """删除 AI 供应商"""
        async with self._lock:
            if provider_id not in self.config_data.get("providers", {}):
                return False

            await self._backup_config()
            del self.config_data["providers"][provider_id]
            await self._save_config()

            return True

    # ========================================================================
    # 提示词管理
    # ========================================================================

    async def get_prompts(self) -> Dict[str, PromptTemplate]:
        """获取所有提示词模板"""
        return {k: PromptTemplate(**v) for k, v in self.config_data.get("prompts", {}).items()}

    async def add_or_update_prompt(self, prompt_id: str, prompt: PromptTemplate) -> PromptTemplate:
        """添加或更新提示词模板"""
        async with self._lock:
            await self._backup_config()

            if "prompts" not in self.config_data:
                self.config_data["prompts"] = {}

            self.config_data["prompts"][prompt_id] = prompt.model_dump()
            await self._save_config()

            return prompt

    async def delete_prompt(self, prompt_id: str) -> bool:
        """删除提示词模板"""
        async with self._lock:
            if prompt_id not in self.config_data.get("prompts", {}):
                return False

            await self._backup_config()
            del self.config_data["prompts"][prompt_id]
            await self._save_config()

            return True

    # ========================================================================
    # Live2D 模型管理
    # ========================================================================

    async def get_live2d_models(self) -> list[Live2DModel]:
        """获取所有 Live2D 模型"""
        return [Live2DModel(**model) for model in self.config_data.get("live2d_models", [])]

    async def add_live2d_model(self, model: Live2DModel) -> Live2DModel:
        """添加 Live2D 模型"""
        async with self._lock:
            await self._backup_config()

            if "live2d_models" not in self.config_data:
                self.config_data["live2d_models"] = []

            # 检查 ID 是否已存在
            existing_ids = [m.get("id") for m in self.config_data["live2d_models"]]
            if model.id in existing_ids:
                # 更新现有模型
                for i, m in enumerate(self.config_data["live2d_models"]):
                    if m.get("id") == model.id:
                        self.config_data["live2d_models"][i] = model.model_dump()
                        break
            else:
                # 添加新模型
                self.config_data["live2d_models"].append(model.model_dump())

            await self._save_config()
            return model

    async def delete_live2d_model(self, model_id: str) -> bool:
        """删除 Live2D 模型"""
        async with self._lock:
            models = self.config_data.get("live2d_models", [])
            original_len = len(models)

            self.config_data["live2d_models"] = [m for m in models if m.get("id") != model_id]

            if len(self.config_data["live2d_models"]) < original_len:
                await self._backup_config()
                await self._save_config()
                return True

            return False

    # ========================================================================
    # 设置管理
    # ========================================================================

    async def get_settings(self) -> AppSettings:
        """获取应用设置"""
        return AppSettings(**self.config_data.get("settings", {}))

    async def update_settings(self, settings: AppSettings) -> AppSettings:
        """更新应用设置"""
        async with self._lock:
            await self._backup_config()
            self.config_data["settings"] = settings.model_dump()
            await self._save_config()
            return settings
