# -*- coding: utf-8 -*-
"""
CraftPilot MCP 工具基类
Author: CraftPilot

本模块提供 MCP 工具的基类定义，供外部开发者继承使用。
"""

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


class MCPToolBase(ABC):
    """
    MCP 工具基类
    
    外部开发者可以继承此类来创建自定义 MCP 工具。
    
    示例用法::
    
        from craftpilot.pypapi.mcp import MCPToolBase
        
        class MyCustomTool(MCPToolBase):
            name = "my_custom_tool"
            description = "我的自定义工具"
            category = "custom"
            timeout = 60
            
            def execute(self, **kwargs) -> dict:
                # 实现工具逻辑
                return {"result": "success"}
    """
    
    # 工具名称（必须覆盖）
    name: str = None
    
    # 工具描述（必须覆盖）
    description: str = None
    
    # 工具分类
    category: str = "general"
    
    # 超时时间（秒）
    timeout: int = 30
    
    # 是否在服务器端执行（默认 True）
    execute_on_server: bool = True
    
    @abstractmethod
    def execute(self, **kwargs) -> dict:
        """
        执行工具逻辑
        
        Args:
            **kwargs: 工具参数
            
        Returns:
            dict: 执行结果，应包含 'success' 字段
        """
        pass
    
    @classmethod
    def get_parameters_schema(cls) -> dict:
        """
        获取工具参数的 JSON Schema
        
        子类可以覆盖此方法来定义参数 schema，
        或者使用 @craftmethod 装饰器自动生成。
        
        Returns:
            dict: JSON Schema 格式的参数定义
        """
        return {
            'type': 'object',
            'properties': {},
            'required': []
        }
    
    @classmethod
    def get_tool_definition(cls) -> dict:
        """
        获取工具的完整定义
        
        Returns:
            dict: MCP 标准格式的工具定义
        """
        return {
            'type': 'function',
            'function': {
                'name': cls.name,
                'description': cls.description,
                'parameters': cls.get_parameters_schema(),
                'timeout': cls.timeout
            }
        }
    
    def validate_parameters(self, parameters: dict) -> Optional[str]:
        """
        验证参数
        
        Args:
            parameters: 传入的参数字典
            
        Returns:
            str: 错误信息，如果验证通过则返回 None
        """
        # 默认实现：不做验证
        # 子类可以覆盖此方法实现自定义验证
        return None
    
    def __call__(self, **kwargs) -> dict:
        """
        调用工具
        
        首先验证参数，然后执行工具逻辑。
        
        Returns:
            dict: 执行结果
        """
        # 验证参数
        error = self.validate_parameters(kwargs)
        if error:
            return {
                'success': False,
                'error': error,
                'error_type': 'validation'
            }
        
        # 执行工具
        try:
            result = self.execute(**kwargs)
            if isinstance(result, dict):
                if 'success' not in result:
                    result['success'] = True
                return result
            else:
                return {'success': True, 'result': result}
        except Exception as e:
            return {
                'success': False,
                'error': str(e),
                'error_type': 'execution'
            }


class MCPToolMixin:
    """
    MCP 工具混入类
    
    可以与 DsonBase 一起使用，为 DsonBase 子类添加 MCP 工具功能。
    
    示例用法::
    
        from craftpilot.pypapi.dson import DsonBase
        from craftpilot.pypapi.mcp import MCPToolMixin, expose_as_mcp
        
        class MyTools(DsonBase, MCPToolMixin):
            if_in_server = False  # 在外部进程执行
            
            @expose_as_mcp(timeout=60, category="custom")
            def my_tool(self, param: String) -> dict:
                return {"result": param.get_input()}
    """
    
    # MCP 工具相关配置
    mcp_enabled: bool = True
    mcp_category: str = "general"
    
    @classmethod
    def get_mcp_tools(cls) -> List[dict]:
        """
        获取类中所有标记为 MCP 工具的方法
        
        Returns:
            List[dict]: MCP 工具定义列表
        """
        tools = []
        for attr_name in dir(cls):
            attr = getattr(cls, attr_name, None)
            if hasattr(attr, '_is_mcp_tool') and attr._is_mcp_tool:
                tools.append({
                    'name': attr.__name__,
                    'func': attr,
                    'timeout': getattr(attr, '_mcp_timeout', 30),
                    'category': getattr(attr, '_mcp_category', cls.mcp_category),
                    'description': attr.__doc__ or f'MCP tool: {attr.__name__}'
                })
        return tools
