"""工具系统基类

定义标准工具接口，统一不同调用形式（LangChain Tool、Function Call、MCP）
"""

from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field, create_model

# ============================================================================
# 标准输入输出模型
# ============================================================================


class ToolInput(BaseModel):
    """标准工具输入"""
    name: str = Field(..., description="工具名称")
    parameters: Dict[str, Any] = Field(default_factory=dict, description="工具参数")
    context: Optional[Dict[str, Any]] = Field(default=None, description="执行上下文")


class ToolOutput(BaseModel):
    """标准工具输出"""
    success: bool = Field(..., description="执行是否成功")
    result: Any = Field(..., description="执行结果")
    error: Optional[str] = Field(default=None, description="错误信息")
    metadata: Dict[str, Any] = Field(default_factory=dict, description="额外元数据")


# ============================================================================
# Function Call 格式抽象（兼容 OpenAI/MiniMax）
# ============================================================================


class FunctionCallDefinition(BaseModel):
    """Function Call 函数定义 - OpenAI 格式"""
    name: str = Field(..., description="函数名称")
    description: str = Field(..., description="函数功能描述")
    parameters: Dict[str, Any] = Field(default_factory=dict, description="JSON Schema 参数定义")

    def to_openai_format(self) -> Dict[str, Any]:
        """转换为 OpenAI Function Call 格式"""
        return {
            "type": "function",
            "function": {
                "name": self.name,
                "description": self.description,
                "parameters": self.parameters
            }
        }


# ============================================================================
# 工具抽象基类
# ============================================================================


class BaseTool(ABC):
    """标准工具基类 - 统一 LangChain Tool 和 Function Call

    属性:
        name: 工具名称
        description: 工具功能描述
        input_schema: JSON Schema 格式的输入参数定义
        category: 工具分类（search, file, datetime, network, system, general）
    """

    name: str
    description: str
    input_schema: Dict[str, Any]
    category: str = "general"

    def __init__(self, **data):
        """初始化工具，确保必需属性存在"""
        super().__init__(**data)
        # 设置默认值
        if not hasattr(self, 'input_schema') or not self.input_schema:
            self.input_schema = self._get_default_schema()

    def _get_default_schema(self) -> Dict[str, Any]:
        """获取默认输入 schema"""
        return {
            "type": "object",
            "properties": {},
            "required": []
        }

    @abstractmethod
    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        """执行工具

        Args:
            parameters: 工具参数
            context: 执行上下文（如用户信息、会话信息等）

        Returns:
            ToolOutput: 标准工具输出
        """
        pass

    # ------ LangChain Tool 转换 ------

    def to_langchain_tool(self):
        """转换为 LangChain @tool 装饰器格式"""
        from langchain.tools import tool
        from pydantic import Field

        # 获取输入 schema
        properties = self.input_schema.get("properties", {})
        required = self.input_schema.get("required", [])

        # 构建 Pydantic 模型用于 LangChain
        field_definitions = {}
        for field_name, field_info in properties.items():
            # 确定字段类型
            field_type = str
            if field_info.get("type") == "integer":
                field_type = int
            elif field_info.get("type") == "number":
                field_type = float
            elif field_info.get("type") == "boolean":
                field_type = bool
            elif field_info.get("type") == "array":
                field_type = list
            elif field_info.get("type") == "object":
                field_type = dict

            field_kwargs = {"description": field_info.get("description", "")}
            if field_name in required:
                field_definitions[field_name] = (field_type, Field(default=..., **field_kwargs))
            else:
                field_definitions[field_name] = (field_type, Field(default=field_info.get("default", ""), **field_kwargs))

        # 创建动态 schema 类
        schema_class = create_model(f"{self.name.capitalize()}Input", **field_definitions)

        # 保存工具实例的引用
        tool_instance = self

        @tool(args_schema=schema_class)
        def langchain_tool_func(**kwargs) -> str:
            """工具函数包装"""
            try:
                # 直接使用 kwargs 作为参数
                result = tool_instance.execute(kwargs)
                if result.success:
                    return str(result.result)
                else:
                    return f"错误: {result.error}"
            except Exception as e:
                return f"执行错误: {str(e)}"

        # 设置工具属性
        langchain_tool_func.name = self.name
        langchain_tool_func.description = self.description

        return langchain_tool_func

    def _get_langchain_schema(self):
        """获取 LangChain 格式的 schema"""

        # 从 input_schema 构建 Pydantic 模型
        properties = self.input_schema.get("properties", {})
        required = self.input_schema.get("required", [])

        # 创建动态 schema 类
        schema_dict = {
            "type": "object",
            "properties": {k: v for k, v in properties.items()},
            "required": required
        }

        # 使用 create_model 动态创建模型（Pydantic V2 兼容）
        field_definitions = {}
        for field_name, field_info in properties.items():
            # 简化类型处理
            field_type = str
            if field_info.get("type") == "integer":
                field_type = int
            elif field_info.get("type") == "number":
                field_type = float
            elif field_info.get("type") == "boolean":
                field_type = bool
            elif field_info.get("type") == "array":
                field_type = list
            elif field_info.get("type") == "object":
                field_type = dict

            field_kwargs = {"description": field_info.get("description", "")}
            if field_name in required:
                # 必填字段：使用 ... 作为默认值
                field_definitions[field_name] = (field_type, Field(default=..., **field_kwargs))
            else:
                # 可选字段：使用配置的默认值
                field_definitions[field_name] = (field_type, Field(default=field_info.get("default", ""), **field_kwargs))

        DynamicSchema = create_model("DynamicSchema", **field_definitions)
        return DynamicSchema

    # ------ Function Call 转换 ------

    def to_function_call(self) -> FunctionCallDefinition:
        """转换为 Function Call 格式"""
        return FunctionCallDefinition(
            name=self.name,
            description=self.description,
            parameters=self.input_schema
        )

    # ------ MCP 格式转换 ------

    def to_mcp_schema(self) -> Dict[str, Any]:
        """转换为 MCP 工具描述格式"""
        return {
            "name": self.name,
            "description": self.description,
            "inputSchema": self.input_schema
        }

    # ------ 便捷方法 ------

    def __repr__(self) -> str:
        return f"<{self.__class__.__name__}(name={self.name}, category={self.category})>"


# ============================================================================
# 工具集合容器
# ============================================================================


class ToolCollection:
    """工具集合 - 管理多个工具"""

    def __init__(self, tools: Optional[List[BaseTool]] = None):
        self._tools: Dict[str, BaseTool] = {}
        if tools:
            for tool in tools:
                self.add(tool)

    def add(self, tool: BaseTool) -> None:
        """添加工具"""
        self._tools[tool.name] = tool

    def get(self, name: str) -> Optional[BaseTool]:
        """获取工具"""
        return self._tools.get(name)

    def remove(self, name: str) -> bool:
        """移除工具"""
        if name in self._tools:
            del self._tools[name]
            return True
        return False

    def list_tools(self) -> List[BaseTool]:
        """列出所有工具"""
        return list(self._tools.values())

    def list_by_category(self, category: str) -> List[BaseTool]:
        """按分类列出工具"""
        return [t for t in self._tools.values() if t.category == category]

    @property
    def categories(self) -> List[str]:
        """获取所有分类"""
        return list(set(t.category for t in self._tools.values()))

    # ------ 格式转换 ------

    def to_langchain_tools(self) -> List:
        """转换为 LangChain 工具列表"""
        return [t.to_langchain_tool() for t in self._tools.values()]

    def to_function_calls(self) -> List[FunctionCallDefinition]:
        """转换为 Function Call 定义列表"""
        return [t.to_function_call() for t in self._tools.values()]

    def to_mcp_schemas(self) -> List[Dict[str, Any]]:
        """转换为 MCP 格式列表"""
        return [t.to_mcp_schema() for t in self._tools.values()]

    def __len__(self) -> int:
        return len(self._tools)

    def __contains__(self, name: str) -> bool:
        return name in self._tools
