"""
组件抽象层：Tool 基础抽象类

定义工具组件的抽象基类，支持 LangGraph 工具注解和标准化接口
"""

from abc import ABC, abstractmethod
from typing import Any, Dict, Optional, Union, Type, List
from langchain_core.tools import BaseTool, tool
from pydantic import BaseModel, Field
import inspect
import functools


class BaseToolComponent(ABC):
    """工具组件基类
    
    为工具提供标准化的接口和生命周期管理
    """
    
    def __init__(self, name: str, description: str = "", enabled: bool = True):
        """初始化工具组件
        
        Args:
            name: 工具名称
            description: 工具描述
            enabled: 是否启用
        """
        self.name = name
        self.description = description
        self.enabled = enabled
        self._tool_instance: Optional[BaseTool] = None
        self._initialized = False
    
    @abstractmethod
    def _create_tool(self) -> BaseTool:
        """创建工具实例，子类必须实现"""
        pass
    
    def initialize(self) -> None:
        """初始化工具"""
        if not self._initialized:
            self._tool_instance = self._create_tool()
            self._initialized = True
    
    def get_tool(self) -> BaseTool:
        """获取工具实例"""
        if not self._initialized:
            self.initialize()
        return self._tool_instance
    
    @property
    def is_initialized(self) -> bool:
        """检查是否已初始化"""
        return self._initialized
    
    def enable(self) -> None:
        """启用工具"""
        self.enabled = True
    
    def disable(self) -> None:
        """禁用工具"""
        self.enabled = False
    
    def __str__(self) -> str:
        status = "enabled" if self.enabled else "disabled"
        return f"{self.__class__.__name__}(name='{self.name}', status='{status}')"
    
    def __repr__(self) -> str:
        return self.__str__()


class SimpleTool(BaseToolComponent):
    """简单工具实现
    
    基于函数的简单工具，自动使用 @tool 装饰器
    """
    
    def __init__(
        self,
        name: str,
        description: str,
        func: callable,
        schema: Optional[Type[BaseModel]] = None,
        return_direct: bool = False
    ):
        """初始化简单工具
        
        Args:
            name: 工具名称
            description: 工具描述
            func: 工具执行函数
            schema: 输入参数 schema
            return_direct: 是否直接返回结果
        """
        super().__init__(name, description)
        self.func = func
        self.schema = schema
        self.return_direct = return_direct
    
    def _create_tool(self) -> BaseTool:
        """创建工具实例"""
        # 使用 @tool 装饰器创建工具
        # 先设置函数的名称和文档
        self.func.__name__ = self.name
        self.func.__doc__ = self.description
        
        if self.schema:
            return tool(
                args_schema=self.schema,
                return_direct=self.return_direct
            )(self.func)
        else:
            return tool(
                return_direct=self.return_direct
            )(self.func)


class AsyncTool(BaseToolComponent):
    """异步工具实现
    
    支持异步操作的工具
    """
    
    def __init__(
        self,
        name: str,
        description: str,
        async_func: callable,
        schema: Optional[Type[BaseModel]] = None,
        return_direct: bool = False
    ):
        """初始化异步工具
        
        Args:
            name: 工具名称
            description: 工具描述
            async_func: 异步工具执行函数
            schema: 输入参数 schema
            return_direct: 是否直接返回结果
        """
        super().__init__(name, description)
        self.async_func = async_func
        self.schema = schema
        self.return_direct = return_direct
    
    def _create_tool(self) -> BaseTool:
        """创建异步工具实例"""
        # 先设置函数的名称和文档
        self.async_func.__name__ = self.name
        self.async_func.__doc__ = self.description
        
        if self.schema:
            return tool(
                args_schema=self.schema,
                return_direct=self.return_direct
            )(self.async_func)
        else:
            return tool(
                return_direct=self.return_direct
            )(self.async_func)


class ConfigurableTool(BaseToolComponent):
    """可配置工具
    
    支持运行时配置的工具
    """
    
    def __init__(
        self,
        name: str,
        description: str,
        base_func: callable,
        config: Optional[Dict[str, Any]] = None,
        schema: Optional[Type[BaseModel]] = None
    ):
        """初始化可配置工具
        
        Args:
            name: 工具名称
            description: 工具描述
            base_func: 基础执行函数
            config: 配置参数
            schema: 输入参数 schema
        """
        super().__init__(name, description)
        self.base_func = base_func
        self.config = config or {}
        self.schema = schema
    
    def _create_tool(self) -> BaseTool:
        """创建可配置工具实例"""
        # 创建带配置的包装函数
        def configured_func(*args, **kwargs):
            # 将配置参数传递给基础函数
            return self.base_func(*args, config=self.config, **kwargs)
        
        # 更新函数签名和文档
        configured_func.__name__ = self.name
        configured_func.__doc__ = self.description
        
        if self.schema:
            return tool(
                args_schema=self.schema
            )(configured_func)
        else:
            return tool()(configured_func)
    
    def update_config(self, new_config: Dict[str, Any]) -> None:
        """更新配置"""
        self.config.update(new_config)
        # 重新初始化工具
        if self._initialized:
            self._initialized = False
            self.initialize()


class ToolRegistry:
    """工具注册表
    
    管理和组织工具组件
    """
    
    def __init__(self):
        self._tools: Dict[str, BaseToolComponent] = {}
        self._categories: Dict[str, List[str]] = {}
    
    def register(self, tool: BaseToolComponent, category: Optional[str] = None) -> None:
        """注册工具
        
        Args:
            tool: 工具实例
            category: 工具分类
        """
        if tool.name in self._tools:
            raise ValueError(f"Tool '{tool.name}' already registered")
        
        self._tools[tool.name] = tool
        
        if category:
            if category not in self._categories:
                self._categories[category] = []
            self._categories[category].append(tool.name)
    
    def get_tool(self, name: str) -> Optional[BaseToolComponent]:
        """获取工具
        
        Args:
            name: 工具名称
            
        Returns:
            工具实例或 None
        """
        return self._tools.get(name)
    
    def get_tools_by_category(self, category: str) -> List[BaseToolComponent]:
        """根据分类获取工具
        
        Args:
            category: 分类名称
            
        Returns:
            工具列表
        """
        tool_names = self._categories.get(category, [])
        return [self._tools[name] for name in tool_names if name in self._tools]
    
    def get_enabled_tools(self) -> List[BaseTool]:
        """获取所有启用的工具
        
        Returns:
            启用的工具列表
        """
        enabled_tools = []
        for tool_component in self._tools.values():
            if tool_component.enabled:
                enabled_tools.append(tool_component.get_tool())
        return enabled_tools
    
    def list_tools(self) -> Dict[str, str]:
        """列出所有工具
        
        Returns:
            工具名称到描述的映射
        """
        return {name: tool.description for name, tool in self._tools.items()}
    
    def enable_tool(self, name: str) -> bool:
        """启用工具
        
        Args:
            name: 工具名称
            
        Returns:
            是否成功
        """
        tool = self._tools.get(name)
        if tool:
            tool.enable()
            return True
        return False
    
    def disable_tool(self, name: str) -> bool:
        """禁用工具
        
        Args:
            name: 工具名称
            
        Returns:
            是否成功
        """
        tool = self._tools.get(name)
        if tool:
            tool.disable()
            return True
        return False


# 全局工具注册表实例
tool_registry = ToolRegistry()


# 便捷装饰器
def component_tool(
    name: Optional[str] = None,
    description: Optional[str] = None,
    category: Optional[str] = None,
    schema: Optional[Type[BaseModel]] = None,
    return_direct: bool = False,
    auto_register: bool = True
):
    """组件工具装饰器
    
    将函数转换为工具组件并可选择自动注册
    
    Args:
        name: 工具名称，默认使用函数名
        description: 工具描述，默认使用函数文档字符串
        category: 工具分类
        schema: 输入参数 schema
        return_direct: 是否直接返回结果
        auto_register: 是否自动注册到全局注册表
    """
    def decorator(func):
        tool_name = name or func.__name__
        tool_description = description or (func.__doc__ or "").strip()
        
        # 创建工具组件
        if inspect.iscoroutinefunction(func):
            tool_component = AsyncTool(
                name=tool_name,
                description=tool_description,
                async_func=func,
                schema=schema,
                return_direct=return_direct
            )
        else:
            tool_component = SimpleTool(
                name=tool_name,
                description=tool_description,
                func=func,
                schema=schema,
                return_direct=return_direct
            )
        
        # 自动注册
        if auto_register:
            tool_registry.register(tool_component, category)
        
        # 返回包装后的函数，保持原有接口
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        
        # 将工具组件添加为函数属性
        wrapper._tool_component = tool_component
        
        return wrapper
    
    return decorator