import os
import re
import json
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from pathlib import Path
from .paths import get_path_manager
from provider.models import DEFAULT_PROVIDERS, get_default_models


class ProviderConfig(BaseModel):
    """单个 Provider 连接配置"""
    api_key: Optional[str] = None
    base_url: Optional[str] = None
    type: str = "openai"  # "openai" 或 "anthropic"


class ModelConfig(BaseModel):
    """单个模型配置"""
    provider: str               # 引用 provider 名称
    model: str                  # 实际模型名称
    temperature: float = 0.7
    max_tokens: int = 32000
    # context_window 已移除，统一从 provider/models.py 获取


class ProviderSection(BaseModel):
    """provider 配置段"""
    default: str = ""                           # 默认模型名，如 "anthropic/claude-opus-4-6"
    models: Dict[str, ModelConfig] = {}         # 模型定义
    providers: Dict[str, ProviderConfig] = {}   # provider 连接配置


class MCPServerConfig(BaseModel):
    name: str
    type: str = "stdio"  # stdio, sse, http
    enabled: bool = True

    # Stdio specific
    command: Optional[str] = None
    args: List[str] = []
    env: Dict[str, str] = {}

    # SSE/HTTP specific
    url: Optional[str] = None
    headers: Dict[str, str] = {}  # HTTP headers (用于 API key 等)

    description: Optional[str] = None


class MCPConfig(BaseModel):
    mcp_servers: List[MCPServerConfig] = []


class AppConfig(BaseModel):
    provider: ProviderSection


class ConfigLoader:
    def __init__(self):
        pass

    def _expand_env_vars(self, value: str) -> str:
        """
        Replace ${VAR} with environment variable value.
        """
        if not isinstance(value, str):
            return value

        pattern = r"\$\{([a-zA-Z0-9_]+)\}"
        match = re.search(pattern, value)
        if match:
            env_var = match.group(1)
            env_value = os.getenv(env_var)
            if env_value:
                return value.replace(match.group(0), env_value)
            return value
        return value

    def _process_dict(self, data: dict) -> dict:
        """
        Recursively process dictionary to expand env vars.
        """
        for key, value in data.items():
            if isinstance(value, dict):
                self._process_dict(value)
            elif isinstance(value, list):
                for i, item in enumerate(value):
                    if isinstance(item, str):
                        value[i] = self._expand_env_vars(item)
                    elif isinstance(item, dict):
                        self._process_dict(item)
            elif isinstance(value, str):
                data[key] = self._expand_env_vars(value)
        return data

    def _load_file(self, path: str) -> dict:
        """
        加载配置文件，支持 JSON 和 YAML 格式
        """
        with open(path, "r", encoding="utf-8") as f:
            if path.endswith(".json"):
                return json.load(f)
            else:
                import yaml
                return yaml.safe_load(f)

    def _parse_provider_section(self, raw: dict) -> dict:
        """
        解析 provider 段：除了 default 和 models 以外的 key 视为 provider 定义
        """
        reserved_keys = {"default", "models"}
        providers = {}
        rest = {}

        for key, value in raw.items():
            if key in reserved_keys:
                rest[key] = value
            elif isinstance(value, dict) and ("type" in value or key in DEFAULT_PROVIDERS):
                # 这是一个 provider 定义（有 type 字段，或匹配已知 provider 名称）
                providers[key] = value
            else:
                rest[key] = value

        rest["providers"] = providers
        return rest

    def _merge_defaults(self, provider_data: dict) -> dict:
        """
        合并内置默认值和配置文件值

        策略：内置为底，配置文件同名的覆盖内置
        """
        # 合并 providers
        merged_providers = {k: dict(v) for k, v in DEFAULT_PROVIDERS.items()}
        for name, config_prov in provider_data.get("providers", {}).items():
            if name in merged_providers:
                merged_providers[name].update(config_prov)
            else:
                merged_providers[name] = config_prov
        provider_data["providers"] = merged_providers

        # 合并 models
        merged_models = get_default_models()
        for name, config_model in provider_data.get("models", {}).items():
            if name in merged_models:
                merged_models[name].update(config_model)
            else:
                merged_models[name] = config_model
        provider_data["models"] = merged_models

        return provider_data

    def load_app_config(self, path: str) -> AppConfig:
        if not os.path.exists(path):
            raise FileNotFoundError(
                f"配置文件未找到: {path}\n"
                f"请创建配置文件，参考 .dundun/config.example.json"
            )

        raw_data = self._load_file(path)

        if not raw_data:
            raise ValueError(f"配置文件为空: {path}")

        processed_data = self._process_dict(raw_data)

        # 解析 provider 段
        if "provider" in processed_data:
            processed_data["provider"] = self._parse_provider_section(
                processed_data["provider"]
            )
            processed_data["provider"] = self._merge_defaults(
                processed_data["provider"]
            )

        return AppConfig(**processed_data)

    def load_mcp_config(self, path: str) -> MCPConfig:
        if not os.path.exists(path):
            return MCPConfig()

        raw_data = self._load_file(path)

        if not raw_data:
            return MCPConfig()

        processed_data = self._process_dict(raw_data)

        if "mcp_servers" not in processed_data:
            return MCPConfig()

        return MCPConfig(**processed_data)


def load_config(filename: str = "config.json") -> AppConfig:
    """
    加载应用配置

    Args:
        filename: 配置文件名（默认 config.json）

    Returns:
        AppConfig 实例
    """
    path_manager = get_path_manager()
    config_file = path_manager.get_config_file(filename)
    return ConfigLoader().load_app_config(str(config_file))


def load_mcp_config(filename: str = "tool.json") -> MCPConfig:
    """
    加载 MCP 配置

    先加载 .dundun/tool.json，再加载 ~/.dundun/tool.json，
    合并 mcp_servers 列表（本地优先，按 name 去重）

    Args:
        filename: 配置文件名（默认 tool.json）

    Returns:
        MCPConfig 实例
    """
    path_manager = get_path_manager()
    config_files = path_manager.get_all_config_files(filename)
    loader = ConfigLoader()

    all_servers = []
    seen_names = set()

    for config_file in config_files:
        mcp_config = loader.load_mcp_config(str(config_file))
        for server in mcp_config.mcp_servers:
            if server.name not in seen_names:
                all_servers.append(server)
                seen_names.add(server.name)

    return MCPConfig(mcp_servers=all_servers)


def load_settings() -> dict:
    """
    加载用户设置（~/.dundun/setting.json）

    Returns:
        设置字典
    """
    path_manager = get_path_manager()
    settings_file = path_manager.get_global_dir() / "setting.json"
    if settings_file.exists():
        try:
            with open(settings_file, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception:
            return {}
    return {}


def save_settings(settings: dict) -> None:
    """
    保存用户设置到 ~/.dundun/setting.json

    Args:
        settings: 设置字典
    """
    path_manager = get_path_manager()
    settings_file = path_manager.get_global_dir() / "setting.json"
    with open(settings_file, "w", encoding="utf-8") as f:
        json.dump(settings, f, indent=2, ensure_ascii=False)
