"""初始化层 - 依赖注入和启动"""
from typing import Dict, Any

from .interfaces.llm_client import LLMClient
from .interfaces.prompt_loader import PromptLoader
from .interfaces.chain_executor import ChainExecutor

from .implementations.clients import (
    QwenClient,
    GeminiClient,
    DeepSeekClient,
    DoubaoClient
)
from .implementations.loaders import YamlPromptLoader
from .implementations.chains import AsyncChainExecutor
from .orchestration import PromptChainProcessor
from foundation.infrastructure.config.config import config_handler


class Bootstrap:
    """启动和依赖注入容器"""

    # 模型客户端映射
    _CLIENT_MAP = {
        "qwen": QwenClient,
        "gemini": GeminiClient,
        "deepseek": DeepSeekClient,
        "doubao": DoubaoClient
    }

    @staticmethod
    def _load_llm_config(model_type: str = None) -> Dict[str, Any]:
        """
        加载大模型API配置（从 config.ini）

        Args:
            model_type: 模型类型，如果为None则从配置文件读取默认值

        Returns:
            配置字典
        """
        # 获取模型类型（优先从 model_setting.yaml 读取默认配置）
        if model_type is None:
            try:
                from foundation.ai.models.model_config_loader import get_model_for_function
                model_type = get_model_for_function("default")
                if model_type:
                    logger.debug(f"LLMChainClient 从 model_setting.yaml 读取默认模型: {model_type}")
                else:
                    model_type = config_handler.get("model", "MODEL_TYPE", "qwen3_5_35b_a3b")
            except Exception as e:
                logger.debug(f"LLMChainClient 从 model_setting.yaml 读取失败: {e}，回退到 config.ini")
                model_type = config_handler.get("model", "MODEL_TYPE", "qwen3_5_35b_a3b")

        model_type = model_type.lower()

        # 构建 DashScope 风格的配置（兼容现有客户端）
        if model_type.startswith("qwen"):
            server_url = config_handler.get(model_type, "DASHSCOPE_SERVER_URL", "")
            model_id = config_handler.get(model_type, "DASHSCOPE_MODEL_ID", "")
            api_key = config_handler.get(model_type, "DASHSCOPE_API_KEY", "")

            # 如果没有 DashScope 配置，尝试读取 QWEN_SERVER_URL 等旧格式
            if not server_url:
                server_url = config_handler.get(model_type, f"{model_type.upper()}_SERVER_URL", "")
                model_id = config_handler.get(model_type, f"{model_type.upper()}_MODEL_ID", "")
                api_key = config_handler.get(model_type, f"{model_type.upper()}_API_KEY", "")

            config = {
                "QWEN_SERVER_URL": server_url,
                "QWEN_MODEL_ID": model_id,
                "QWEN_API_KEY": api_key,
            }
        elif model_type == "gemini":
            config = {
                "GEMINI_SERVER_URL": config_handler.get("gemini", "GEMINI_SERVER_URL", ""),
                "GEMINI_MODEL_ID": config_handler.get("gemini", "GEMINI_MODEL_ID", ""),
                "GEMINI_API_KEY": config_handler.get("gemini", "GEMINI_API_KEY", ""),
            }
        elif model_type == "deepseek":
            config = {
                "DEEPSEEK_SERVER_URL": config_handler.get("deepseek", "DEEPSEEK_SERVER_URL", ""),
                "DEEPSEEK_MODEL_ID": config_handler.get("deepseek", "DEEPSEEK_MODEL_ID", ""),
                "DEEPSEEK_API_KEY": config_handler.get("deepseek", "DEEPSEEK_API_KEY", ""),
            }
        elif model_type == "doubao":
            config = {
                "DOUBAO_SERVER_URL": config_handler.get("doubao", "DOUBAO_SERVER_URL", ""),
                "DOUBAO_MODEL_ID": config_handler.get("doubao", "DOUBAO_MODEL_ID", ""),
                "DOUBAO_API_KEY": config_handler.get("doubao", "DOUBAO_API_KEY", ""),
            }
        elif model_type.startswith("shutian"):
            # 蜀天模型系列
            server_url = config_handler.get("shutian", "SHUTIAN_35B_SERVER_URL", "")
            model_id = config_handler.get("shutian", "SHUTIAN_35B_MODEL_ID", "")
            api_key = config_handler.get("shutian", "SHUTIAN_35B_API_KEY", "")

            # 根据具体模型类型选择不同端口
            if "122b" in model_type:
                server_url = config_handler.get("shutian", "SHUTIAN_122B_SERVER_URL", server_url)
                model_id = config_handler.get("shutian", "SHUTIAN_122B_MODEL_ID", model_id)
            elif "8b" in model_type and "35b" not in model_type:
                server_url = config_handler.get("shutian", "SHUTIAN_8B_SERVER_URL", server_url)
                model_id = config_handler.get("shutian", "SHUTIAN_8B_MODEL_ID", model_id)

            config = {
                "QWEN_SERVER_URL": server_url,
                "QWEN_MODEL_ID": model_id,
                "QWEN_API_KEY": api_key,
            }
        else:
            raise ValueError(f"不支持的模型类型: {model_type}")

        # 添加通用配置
        config["timeout"] = int(config_handler.get("llm_keywords", "TIMEOUT", "60"))
        config["max_retries"] = int(config_handler.get("llm_keywords", "MAX_RETRIES", "2"))

        return config

    @staticmethod
    def _create_llm_client(model_type: str, config: Dict[str, Any] = None) -> LLMClient:
        """
        创建大模型客户端

        Args:
            model_type: 模型类型（qwen/gemini/deepseek/doubao）
            config: 配置字典（可选，如果不提供则从 config.ini 加载）

        Returns:
            大模型客户端实例
        """
        model_type_lower = model_type.lower()

        # 将 qwen3_5_xx 和 shutian 类型映射为 qwen 客户端（都是OpenAI兼容API）
        client_type = model_type_lower
        if model_type_lower.startswith("qwen") or model_type_lower.startswith("lq_qwen") or model_type_lower.startswith("shutian"):
            client_type = "qwen"

        if client_type not in Bootstrap._CLIENT_MAP:
            raise ValueError(
                f"不支持的模型类型: {model_type}，"
                f"支持的类型: {', '.join(Bootstrap._CLIENT_MAP.keys())}"
            )

        # 如果没有传入配置，从 config.ini 加载
        if config is None:
            config = Bootstrap._load_llm_config(model_type_lower)

        # 创建客户端
        client_class = Bootstrap._CLIENT_MAP[client_type]
        return client_class(config)

    @staticmethod
    def _create_prompt_loader(
        prompts_dir: str = "config/prompts"
    ) -> PromptLoader:
        """
        创建提示词加载器

        Args:
            prompts_dir: 提示词目录路径

        Returns:
            提示词加载器实例
        """
        return YamlPromptLoader(prompts_dir)

    @staticmethod
    def _create_chain_executor(
        llm_client: LLMClient,
        prompt_loader: PromptLoader,
        temperature: float = None,
        max_tokens: int = None
    ) -> ChainExecutor:
        """
        创建提示链执行器

        Args:
            llm_client: 大模型客户端
            prompt_loader: 提示词加载器
            temperature: 温度参数（可选）
            max_tokens: 最大token数（可选）

        Returns:
            提示链执行器实例
        """
        # 从 config.ini 读取默认值
        default_temperature = temperature or float(config_handler.get("llm_keywords", "TEMPERATURE", "0.3"))
        default_max_tokens = max_tokens or int(config_handler.get("llm_keywords", "MAX_TOKENS", "1024"))

        return AsyncChainExecutor(
            llm_client=llm_client,
            prompt_loader=prompt_loader,
            default_temperature=default_temperature,
            default_max_tokens=default_max_tokens
        )

    @staticmethod
    def create_processor(
        model_type: str = None,
        prompts_dir: str = "config/prompts",
        temperature: float = None,
        max_tokens: int = None
    ) -> PromptChainProcessor:
        """
        创建提示链处理器

        Args:
            model_type: 模型类型（qwen/gemini/deepseek/doubao），
                       如果为None则从配置文件读取
            prompts_dir: 提示词目录路径
            temperature: 温度参数（可选）
            max_tokens: 最大token数（可选）

        Returns:
            提示链处理器实例
        """
        # 确定模型类型（优先从 model_setting.yaml 读取默认配置）
        if model_type is None:
            try:
                from foundation.ai.models.model_config_loader import get_model_for_function
                model_type = get_model_for_function("default")
                if model_type:
                    logger.debug(f"PromptChainProcessor 从 model_setting.yaml 读取默认模型: {model_type}")
                else:
                    model_type = config_handler.get("model", "MODEL_TYPE", "qwen3_5_35b_a3b")
            except Exception as e:
                logger.debug(f"PromptChainProcessor 从 model_setting.yaml 读取失败: {e}，回退到 config.ini")
                model_type = config_handler.get("model", "MODEL_TYPE", "qwen3_5_35b_a3b")

        # 创建组件
        llm_client = Bootstrap._create_llm_client(model_type)
        prompt_loader = Bootstrap._create_prompt_loader(prompts_dir)
        chain_executor = Bootstrap._create_chain_executor(
            llm_client,
            prompt_loader,
            temperature,
            max_tokens
        )

        # 创建处理器
        return PromptChainProcessor(
            llm_client=llm_client,
            prompt_loader=prompt_loader,
            chain_executor=chain_executor
        )

    @staticmethod
    def get_supported_models() -> list[str]:
        """
        获取支持的模型类型列表

        Returns:
            模型类型列表
        """
        return list(Bootstrap._CLIENT_MAP.keys())
