"""工具基础接口定义"""
import time
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional

from app.models.tool_model import ToolType, ToolStatus
from app.schemas.tool_schema import ToolParameter, ParameterType, ToolResult


class BaseTool(ABC):
    """所有工具的基础抽象类"""
    
    def __init__(self, tool_id: str, config: Dict[str, Any]):
        """初始化工具
        
        Args:
            tool_id: 工具ID
            config: 工具配置
        """
        self.tool_id = tool_id
        self.config = config
        self._status = ToolStatus.AVAILABLE
    
    @property
    @abstractmethod
    def name(self) -> str:
        """工具名称"""
        pass
    
    @property
    @abstractmethod
    def description(self) -> str:
        """工具描述"""
        pass
    
    @property
    @abstractmethod
    def tool_type(self) -> ToolType:
        """工具类型"""
        pass
    
    @property
    def version(self) -> str:
        """工具版本"""
        return self.config.get("version", "1.0.0")
    
    @property
    def status(self) -> ToolStatus:
        """工具状态"""
        return self._status
    
    @status.setter
    def status(self, value: ToolStatus):
        """设置工具状态"""
        self._status = value
    
    @property
    @abstractmethod
    def parameters(self) -> List[ToolParameter]:
        """工具参数定义"""
        pass
    
    @property
    def tags(self) -> List[str]:
        """工具标签"""
        return self.config.get("tags", [])
    
    def validate_parameters(self, parameters: Dict[str, Any]) -> Dict[str, str]:
        """验证参数
        
        Args:
            parameters: 输入参数
            
        Returns:
            验证错误字典，空字典表示验证通过
        """
        errors = {}
        param_definitions = {p.name: p for p in self.parameters}
        
        # 检查必需参数
        for param_def in self.parameters:
            if param_def.required and param_def.name not in parameters:
                errors[param_def.name] = f"Required parameter '{param_def.name}' is missing"
        
        # 检查参数类型和约束
        for param_name, param_value in parameters.items():
            if param_name not in param_definitions:
                continue
                
            param_def = param_definitions[param_name]
            
            # 类型检查
            if not self._validate_parameter_type(param_value, param_def):
                errors[param_name] = f"Parameter '{param_name}' has invalid type, expected {param_def.type}"
            
            # 约束检查
            constraint_error = self._validate_parameter_constraints(param_value, param_def)
            if constraint_error:
                errors[param_name] = constraint_error
        
        return errors
    
    def _validate_parameter_type(self, value: Any, param_def: ToolParameter) -> bool:
        """验证参数类型"""
        if value is None:
            return not param_def.required
        
        type_mapping = {
            ParameterType.STRING: str,
            ParameterType.INTEGER: int,
            ParameterType.NUMBER: (int, float),
            ParameterType.BOOLEAN: bool,
            ParameterType.ARRAY: list,
            ParameterType.OBJECT: dict
        }
        
        expected_type = type_mapping.get(param_def.type)
        if expected_type:
            return isinstance(value, expected_type)
        
        return True
    
    def _validate_parameter_constraints(self, value: Any, param_def: ToolParameter) -> Optional[str]:
        """验证参数约束"""
        if value is None:
            return None
        
        # 枚举值检查
        if param_def.enum and value not in param_def.enum:
            return f"Value must be one of {param_def.enum}"
        
        # 数值范围检查
        if param_def.type in [ParameterType.INTEGER, ParameterType.NUMBER]:
            if param_def.minimum is not None and value < param_def.minimum:
                return f"Value must be >= {param_def.minimum}"
            if param_def.maximum is not None and value > param_def.maximum:
                return f"Value must be <= {param_def.maximum}"
        
        # 字符串模式检查
        if param_def.type == ParameterType.STRING and param_def.pattern:
            import re
            if not re.match(param_def.pattern, str(value)):
                return f"Value must match pattern: {param_def.pattern}"
        
        return None
    
    @abstractmethod
    async def execute(self, **kwargs) -> ToolResult:
        """执行工具
        
        Args:
            **kwargs: 工具参数
            
        Returns:
            执行结果
        """
        pass
    
    async def safe_execute(self, **kwargs) -> ToolResult:
        """安全执行工具（包含参数验证和异常处理）
        
        Args:
            **kwargs: 工具参数
            
        Returns:
            执行结果
        """
        start_time = time.time()
        
        try:
            # 参数验证
            validation_errors = self.validate_parameters(kwargs)
            if validation_errors:
                execution_time = time.time() - start_time
                error_msg = "; ".join([f"{k}: {v}" for k, v in validation_errors.items()])
                return ToolResult.error_result(
                    error=f"Parameter validation failed: {error_msg}",
                    error_code="VALIDATION_ERROR",
                    execution_time=execution_time
                )
            
            # 执行工具
            result = await self.execute(**kwargs)
            return result
            
        except Exception as e:
            execution_time = time.time() - start_time
            return ToolResult.error_result(
                error=str(e),
                error_code="EXECUTION_ERROR",
                execution_time=execution_time
            )
    
    def to_langchain_tool(self, operation: Optional[str] = None):
        """转换为Langchain工具格式
        
        Args:
            operation: 特定操作（适用于有操作的工具）
        """
        from app.core.tools.langchain_adapter import LangchainAdapter
        return LangchainAdapter.convert_tool(self, operation)
    
    def __repr__(self):
        return f"<{self.__class__.__name__}(id={self.tool_id}, name={self.name})>"