"""内置工具实现

提供常用的内置工具：搜索、文件操作、时间、URL、系统命令等
"""

import json
import logging
import math
import re
import subprocess
from datetime import datetime, timedelta
from pathlib import Path
from typing import Any, Dict, Optional
from urllib.error import HTTPError, URLError
from urllib.parse import quote
from urllib.request import Request, urlopen

from .base import BaseTool, ToolOutput

logger = logging.getLogger("agent")


# ============================================================================
# 计算器工具
# ============================================================================


class CalculatorTool(BaseTool):
    """计算器工具 - 支持数学运算"""

    name = "calculator"
    description = "执行数学计算。支持基本运算（+、-、*、/、^、%）、数学函数（sqrt、sin、cos、tan、log、floor、ceil）和常量（pi、e）。"
    category = "general"

    input_schema = {
        "type": "object",
        "properties": {
            "expression": {
                "type": "string",
                "description": "要计算的数学表达式，如 '2 + 3 * 4' 或 'sqrt(16)'"
            }
        },
        "required": ["expression"]
    }

    CONSTANTS = {
        "pi": math.pi,
        "e": math.e,
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        try:
            expr = parameters.get("expression", "").strip()
            if not expr:
                return ToolOutput(success=False, result=None, error="表达式不能为空")

            # 预处理表达式
            expr = self._preprocess_expression(expr)

            # 使用安全计算器
            result = self._safe_eval(expr)

            # 格式化结果
            if isinstance(result, float) and result == int(result):
                result_str = str(int(result))
            else:
                result_str = str(round(result, 10))

            return ToolOutput(
                success=True,
                result=result_str,
                metadata={"expression": expr}
            )
        except ValueError as e:
            return ToolOutput(success=False, result=None, error=f"计算错误: {str(e)}")
        except Exception as e:
            return ToolOutput(success=False, result=None, error=f"计算错误: {str(e)}")

    def _preprocess_expression(self, expr: str) -> str:
        """预处理表达式"""
        # 替换 ^ 为 **
        expr = expr.replace("^", "**")

        # 替换常见函数名
        replacements = [
            (r"\bsqrt\(", "math.sqrt("),
            (r"\bsin\(", "math.sin("),
            (r"\bcos\(", "math.cos("),
            (r"\btan\(", "math.tan("),
            (r"\blog10\(", "math.log10("),
            (r"\blog\(", "math.log("),
            (r"\bfloor\(", "math.floor("),
            (r"\bceil\(", "math.ceil("),
        ]

        for pattern, replacement in replacements:
            expr = re.sub(pattern, replacement, expr, flags=re.IGNORECASE)

        # 替换常量
        for const_name, const_value in self.CONSTANTS.items():
            expr = re.sub(rf"\b{const_name}\b", str(const_value), expr, flags=re.IGNORECASE)

        return expr

    def _safe_eval(self, expr: str) -> float:
        """安全地计算表达式 - 使用 AST 解析而非 eval"""
        import ast
        import operator

        # 定义允许的操作
        ops = {
            ast.Add: operator.add,
            ast.Sub: operator.sub,
            ast.Mult: operator.mul,
            ast.Div: operator.truediv,
            ast.FloorDiv: operator.floordiv,
            ast.Mod: operator.mod,
            ast.Pow: operator.pow,
            ast.UAdd: operator.pos,
            ast.USub: operator.neg,
        }

        funcs = {
            'abs': abs,
            'round': round,
            'min': min,
            'max': max,
            'pow': pow,
            'math.sqrt': math.sqrt,
            'math.sin': math.sin,
            'math.cos': math.cos,
            'math.tan': math.tan,
            'math.log10': math.log10,
            'math.log': math.log,
            'math.floor': math.floor,
            'math.ceil': math.ceil,
        }

        def eval_node(node):
            # Python 3.8+ 使用 ast.Constant
            if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
                return node.value
            elif isinstance(node, ast.BinOp):
                left = eval_node(node.left)
                right = eval_node(node.right)
                op_type = type(node.op)
                if op_type in ops:
                    return ops[op_type](left, right)
                raise ValueError(f"不支持的操作: {op_type.__name__}")
            elif isinstance(node, ast.UnaryOp):
                operand = eval_node(node.operand)
                op_type = type(node.op)
                if op_type in ops:
                    return ops[op_type](operand)
                raise ValueError(f"不支持的操作: {op_type.__name__}")
            elif isinstance(node, ast.Call):
                func_name = getattr(node.func, 'id', None)
                if func_name in funcs:
                    args = [eval_node(arg) for arg in node.args]
                    return funcs[func_name](*args)
                raise ValueError(f"不支持的函数: {func_name}")
            elif isinstance(node, ast.Name):
                if node.id in self.CONSTANTS:
                    return self.CONSTANTS[node.id]
                raise ValueError(f"不支持的变量: {node.id}")
            else:
                raise ValueError(f"不支持的表达式类型: {type(node).__name__}")

        # 解析 AST
        tree = ast.parse(expr, mode='eval')
        return eval_node(tree.body)


# ============================================================================
# RAG 文档检索工具
# ============================================================================


class SearchDocumentsTool(BaseTool):
    """RAG 文档检索工具"""

    name = "search_documents"
    description = "搜索知识库中的相关文档。当用户询问关于项目文档、技术细节、或需要从知识库中获取信息时使用此工具。"
    category = "search"

    input_schema = {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "搜索查询关键词或问题"
            }
        },
        "required": ["query"]
    }

    def __init__(self, **data):
        super().__init__(**data)
        self._retriever = None

    def _get_retriever(self):
        """获取检索器"""
        if self._retriever is not None:
            return self._retriever

        try:
            import os
            import sys
            from pathlib import Path

            from langchain_chroma import Chroma
            from langchain_ollama import OllamaEmbeddings

            # 尝试多种方式找到项目根目录
            project_root = None
            for base in [Path(__file__).parent.parent.parent, Path.cwd(), Path(os.getcwd())]:
                # 检查是否存在 src/rag 目录
                if (base / "src" / "rag").exists() or (base / "rag").exists():
                    project_root = base
                    break

            # 如果没找到，尝试使用环境变量或默认位置
            if project_root is None:
                # 尝试从当前工作目录向上查找
                current = Path.cwd()
                for _ in range(5):
                    if (current / "src" / "rag").exists():
                        project_root = current
                        break
                    current = current.parent
                if project_root is None:
                    project_root = Path.cwd()

            # 添加到 sys.path
            project_root_str = str(project_root)
            if project_root_str not in sys.path:
                sys.path.insert(0, project_root_str)

            # 导入配置 - 使用完整路径
            import sys
            from pathlib import Path
            project_root = Path(__file__).parent.parent.parent
            if str(project_root) not in sys.path:
                sys.path.insert(0, str(project_root))

            from src.config.agent import config as agent_config
            try:
                from src.rag.retriever import create_retriever
            except ImportError:
                from rag.retriever import create_retriever

            # 获取 chroma_dir
            chroma_dir = agent_config.chroma_dir
            try:
                from src.rag.config import config as rag_config
                top_k = rag_config.top_k
                embedding_model = rag_config.embedding_model
            except ImportError:
                from rag.config import config as rag_config
                top_k = rag_config.top_k
                embedding_model = rag_config.embedding_model

            vector_store = Chroma(
                persist_directory=chroma_dir,
                embedding_function=OllamaEmbeddings(
                    model=embedding_model
                ),
            )

            self._retriever = create_retriever(
                vector_store=vector_store,
                top_k=top_k,
            )

            logger.info("[SearchDocumentsTool] RAG 检索器初始化完成")
            return self._retriever

        except Exception as e:
            logger.warning(f"[SearchDocumentsTool] RAG 初始化失败: {e}")
            return None

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        query = parameters.get("query", "")

        if not query:
            return ToolOutput(success=False, result=None, error="查询不能为空")

        retriever = self._get_retriever()
        if retriever is None:
            return ToolOutput(
                success=False,
                result=None,
                error="知识库未初始化，请先运行 agent init"
            )

        try:
            docs = retriever.invoke(query)

            if not docs:
                return ToolOutput(success=True, result="未找到相关内容")

            results = []
            for i, doc in enumerate(docs, 1):
                content = doc.page_content[:500]
                source = doc.metadata.get("source", "未知来源")
                results.append(f"--- 文档 {i} (来源: {source}) ---\n{content}")

            return ToolOutput(
                success=True,
                result="\n\n".join(results),
                metadata={"count": len(docs)}
            )

        except Exception as e:
            logger.error(f"[SearchDocumentsTool] 检索错误: {e}")
            return ToolOutput(success=False, result=None, error=f"检索出错: {str(e)}")


# ============================================================================
# 搜索工具
# ============================================================================


class WebSearchTool(BaseTool):
    """网络搜索工具"""

    name = "web_search"
    description = "搜索互联网获取最新信息。使用搜索引擎查询关键词，获取相关网页摘要。"
    category = "search"

    input_schema = {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "搜索关键词"
            },
            "num_results": {
                "type": "integer",
                "description": "返回结果数量，默认 5",
                "default": 5
            }
        },
        "required": ["query"]
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        query = parameters.get("query", "")
        num_results = parameters.get("num_results", 5)

        if not query:
            return ToolOutput(success=False, result=None, error="查询不能为空")

        try:
            # 使用 DuckDuckGo Lite API（无需 API Key）
            url = f"https://lite.duckduckgo.com/lite/?q={quote(query)}&format=json"

            with urlopen(url, timeout=10) as response:
                data = json.loads(response.read().decode('utf-8'))

            results = []
            for i, item in enumerate(data.get('Results', [])[:num_results], 1):
                title = item.get('Text', '')
                url = item.get('URL', '')
                results.append(f"{i}. {title}\n   {url}")

            if not results:
                return ToolOutput(success=True, result="未找到相关结果")

            return ToolOutput(
                success=True,
                result="\n".join(results),
                metadata={"query": query, "count": len(results)}
            )

        except Exception as e:
            logger.error(f"[WebSearchTool] 搜索错误: {e}")
            return ToolOutput(success=False, result=None, error=f"搜索出错: {str(e)}")


# ============================================================================
# 时间工具
# ============================================================================


class GetCurrentTimeTool(BaseTool):
    """获取当前时间"""

    name = "get_current_time"
    description = "获取当前时间。支持不同时区，可返回格式化的时间字符串。"
    category = "datetime"

    input_schema = {
        "type": "object",
        "properties": {
            "timezone": {
                "type": "string",
                "description": "时区名称，如 'Asia/Shanghai'、'UTC'、'America/New_York'。默认为本地时区。"
            },
            "format": {
                "type": "string",
                "description": "时间格式，如 '%Y-%m-%d %H:%M:%S'。默认为 '%Y-%m-%d %H:%M:%S'。"
            }
        },
        "required": []
    }

    # 常用时区映射
    TIMEZONE_MAP = {
        "beijing": "Asia/Shanghai",
        "shanghai": "Asia/Shanghai",
        "tokyo": "Asia/Tokyo",
        "london": "Europe/London",
        "nyc": "America/New_York",
        "new york": "America/New_York",
        "utc": "UTC",
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        timezone_str = parameters.get("timezone", "")
        format_str = parameters.get("format", "%Y-%m-%d %H:%M:%S")

        try:
            # 解析时区
            if timezone_str:
                tz = timezone_str.lower()
                if tz in self.TIMEZONE_MAP:
                    timezone_str = self.TIMEZONE_MAP[tz]
            else:
                timezone_str = None

            # 获取时间
            if timezone_str:
                import pytz
                tz = pytz.timezone(timezone_str)
                now = datetime.now(tz)
            else:
                now = datetime.now()

            # 格式化
            result = now.strftime(format_str)

            return ToolOutput(
                success=True,
                result=result,
                metadata={
                    "timezone": str(now.tzinfo) if now.tzinfo else "本地",
                    "iso_format": now.isoformat()
                }
            )

        except Exception as e:
            return ToolOutput(success=False, result=None, error=f"获取时间失败: {str(e)}")


class ParseDateTool(BaseTool):
    """解析日期字符串"""

    name = "parse_date"
    description = "解析自然语言日期字符串为标准日期格式，如 '下周五'、'3天后'、'2024年1月1日'。"
    category = "datetime"

    input_schema = {
        "type": "object",
        "properties": {
            "date_string": {
                "type": "string",
                "description": "自然语言日期字符串，如 '下周五'、'3天后'、'2024年1月1日'"
            },
            "reference_date": {
                "type": "string",
                "description": "参考日期，格式为 YYYY-MM-DD，默认为今天"
            }
        },
        "required": ["date_string"]
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        date_string = parameters.get("date_string", "")
        reference_str = parameters.get("reference_date", "")

        try:
            # 解析参考日期
            if reference_str:
                reference = datetime.strptime(reference_str, "%Y-%m-%d")
            else:
                reference = datetime.now()

            # 解析日期字符串
            result = self._parse(date_string, reference)

            if result:
                return ToolOutput(
                    success=True,
                    result=result.strftime("%Y-%m-%d %H:%M:%S"),
                    metadata={"weekday": result.strftime("%A")}
                )
            else:
                return ToolOutput(success=False, result=None, error="无法解析日期")

        except Exception as e:
            return ToolOutput(success=False, result=None, error=f"解析日期失败: {str(e)}")

    def _parse(self, date_str: str, reference: datetime) -> Optional[datetime]:
        """解析日期字符串"""
        date_str = date_str.lower().strip()

        # 相对日期
        if "天后" in date_str or "天之后" in date_str:
            days = int(re.search(r'\d+', date_str).group())
            return reference + timedelta(days=days)

        if "周后" in date_str or "周之后" in date_str:
            weeks = int(re.search(r'\d+', date_str).group())
            return reference + timedelta(weeks=weeks)

        if "月后" in date_str or "月之后" in date_str:
            months = int(re.search(r'\d+', date_str).group())
            return self._add_months(reference, months)

        if "年后" in date_str:
            years = int(re.search(r'\d+', date_str).group())
            return self._add_years(reference, years)

        # 特殊日期
        if "今天" in date_str:
            return reference
        if "明天" in date_str:
            return reference + timedelta(days=1)
        if "后天" in date_str:
            return reference + timedelta(days=2)

        weekdays = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
        for i, day in enumerate(weekdays):
            if day in date_str or f"星期{i+1}" in date_str:
                target_weekday = i
                current_weekday = reference.weekday()
                days_ahead = target_weekday - current_weekday
                if days_ahead <= 0:
                    days_ahead += 7
                if "下" in date_str:
                    days_ahead += 7
                return reference + timedelta(days=days_ahead)

        return None

    def _add_months(self, dt: datetime, months: int) -> datetime:
        month = dt.month + months
        year = dt.year + (month - 1) // 12
        month = (month - 1) % 12 + 1
        day = min(dt.day, [31, 29 if year % 4 == 0 else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1])
        return dt.replace(year=year, month=month, day=day)

    def _add_years(self, dt: datetime, years: int) -> datetime:
        try:
            return dt.replace(year=dt.year + years)
        except ValueError:
            return dt.replace(year=dt.year + years, day=28)


# ============================================================================
# 文件操作工具
# ============================================================================


class ReadFileTool(BaseTool):
    """读取文件工具"""

    name = "read_file"
    description = "读取文件内容。支持文本文件和代码文件，返回文件内容。"
    category = "file"

    input_schema = {
        "type": "object",
        "properties": {
            "path": {
                "type": "string",
                "description": "文件路径"
            },
            "encoding": {
                "type": "string",
                "description": "文件编码，默认 utf-8"
            },
            "max_lines": {
                "type": "integer",
                "description": "最大读取行数，默认读取全部"
            }
        },
        "required": ["path"]
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        path = parameters.get("path", "")
        encoding = parameters.get("encoding", "utf-8")
        max_lines = parameters.get("max_lines")

        if not path:
            return ToolOutput(success=False, result=None, error="文件路径不能为空")

        try:
            file_path = Path(path).expanduser().resolve()

            if not file_path.exists():
                return ToolOutput(success=False, result=None, error=f"文件不存在: {path}")

            if not file_path.is_file():
                return ToolOutput(success=False, result=None, error=f"不是文件: {path}")

            with open(file_path, 'r', encoding=encoding) as f:
                if max_lines:
                    lines = [f.readline() for _ in range(max_lines)]
                    content = ''.join(lines)
                else:
                    content = f.read()

            return ToolOutput(
                success=True,
                result=content,
                metadata={
                    "path": str(file_path),
                    "size": file_path.stat().st_size,
                    "lines": len(content.splitlines())
                }
            )

        except UnicodeDecodeError:
            return ToolOutput(success=False, result=None, error="文件编码错误")
        except Exception as e:
            return ToolOutput(success=False, result=None, error=f"读取文件失败: {str(e)}")


class WriteFileTool(BaseTool):
    """写入文件工具"""

    name = "write_file"
    description = "写入内容到文件。如果文件不存在则创建，如果文件存在则覆盖。"
    category = "file"

    input_schema = {
        "type": "object",
        "properties": {
            "path": {
                "type": "string",
                "description": "文件路径"
            },
            "content": {
                "type": "string",
                "description": "要写入的内容"
            },
            "encoding": {
                "type": "string",
                "description": "文件编码，默认 utf-8"
            },
            "append": {
                "type": "boolean",
                "description": "是否追加模式，默认 false（覆盖）"
            }
        },
        "required": ["path", "content"]
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        path = parameters.get("path", "")
        content = parameters.get("content", "")
        encoding = parameters.get("encoding", "utf-8")
        append = parameters.get("append", False)

        if not path:
            return ToolOutput(success=False, result=None, error="文件路径不能为空")

        try:
            file_path = Path(path).expanduser().resolve()

            # 创建父目录
            file_path.parent.mkdir(parents=True, exist_ok=True)

            # 写入文件
            mode = 'a' if append else 'w'
            with open(file_path, mode, encoding=encoding) as f:
                f.write(content)

            return ToolOutput(
                success=True,
                result=f"已写入 {len(content)} 字符到 {file_path}",
                metadata={
                    "path": str(file_path),
                    "bytes_written": len(content.encode(encoding))
                }
            )

        except Exception as e:
            return ToolOutput(success=False, result=None, error=f"写入文件失败: {str(e)}")


class ListDirectoryTool(BaseTool):
    """列出目录工具"""

    name = "list_directory"
    description = "列出目录中的文件和子目录。支持查看目录结构和文件信息。"
    category = "file"

    input_schema = {
        "type": "object",
        "properties": {
            "path": {
                "type": "string",
                "description": "目录路径，默认为当前目录"
            },
            "include_hidden": {
                "type": "boolean",
                "description": "是否包含隐藏文件，默认 false"
            }
        },
        "required": []
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        path = parameters.get("path", ".")
        include_hidden = parameters.get("include_hidden", False)

        try:
            dir_path = Path(path).expanduser().resolve()

            if not dir_path.exists():
                return ToolOutput(success=False, result=None, error=f"目录不存在: {path}")

            if not dir_path.is_dir():
                return ToolOutput(success=False, result=None, error=f"不是目录: {path}")

            items = []
            for item in sorted(dir_path.iterdir()):
                if not include_hidden and item.name.startswith('.'):
                    continue

                item_type = "dir" if item.is_dir() else "file"
                size = item.stat().st_size if item.is_file() else 0
                items.append(f"{item.name} ({item_type}, {size} bytes)")

            if not items:
                return ToolOutput(success=True, result="目录为空")

            return ToolOutput(
                success=True,
                result="\n".join(items),
                metadata={"path": str(dir_path), "count": len(items)}
            )

        except Exception as e:
            return ToolOutput(success=False, result=None, error=f"列出目录失败: {str(e)}")


# ============================================================================
# 网络工具
# ============================================================================


class FetchUrlTool(BaseTool):
    """获取网页内容"""

    name = "fetch_url"
    description = "获取指定 URL 的网页内容。可用于获取网页标题和内容摘要。"
    category = "network"

    input_schema = {
        "type": "object",
        "properties": {
            "url": {
                "type": "string",
                "description": "要获取的 URL"
            },
            "max_length": {
                "type": "integer",
                "description": "最大获取字符数，默认 2000"
            }
        },
        "required": ["url"]
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        url = parameters.get("url", "")
        max_length = parameters.get("max_length", 2000)

        if not url:
            return ToolOutput(success=False, result=None, error="URL 不能为空")

        # 确保 URL 有协议
        if not url.startswith(('http://', 'https://')):
            url = 'https://' + url

        try:
            request = Request(url, headers={
                'User-Agent': 'Mozilla/5.0 (compatible; AgentBot/1.0)'
            })

            with urlopen(request, timeout=10) as response:
                content = response.read().decode('utf-8')

                # 提取标题
                title_match = re.search(r'<title>(.*?)</title>', content, re.IGNORECASE)
                title = title_match.group(1) if title_match else "无标题"

                # 去除 HTML 标签
                text = re.sub(r'<[^>]+>', '', content)
                text = re.sub(r'\s+', ' ', text).strip()

                if len(text) > max_length:
                    text = text[:max_length] + "..."

                result = f"标题: {title}\n\n{text}"

                return ToolOutput(
                    success=True,
                    result=result,
                    metadata={
                        "url": url,
                        "status_code": response.status,
                        "content_length": len(content)
                    }
                )

        except HTTPError as e:
            return ToolOutput(success=False, result=None, error=f"HTTP 错误: {e.code} {e.reason}")
        except URLError as e:
            return ToolOutput(success=False, result=None, error=f"URL 错误: {str(e.reason)}")
        except Exception as e:
            return ToolOutput(success=False, result=None, error=f"获取失败: {str(e)}")


# ============================================================================
# 系统工具
# ============================================================================


class ExecuteCommandTool(BaseTool):
    """执行系统命令"""

    name = "execute_command"
    description = "执行系统命令并返回输出。注意：此工具具有系统访问权限，请谨慎使用。"
    category = "system"

    input_schema = {
        "type": "object",
        "properties": {
            "command": {
                "type": "string",
                "description": "要执行的系统命令"
            },
            "timeout": {
                "type": "integer",
                "description": "超时时间（秒），默认 30"
            }
        },
        "required": ["command"]
    }

    # 安全限制 - 只允许特定命令
    ALLOWED_COMMANDS = {
        "ls", "dir", "pwd", "cat", "head", "tail", "grep", "find",
        "git", "python", "pip", "uv", "npm", "node", "cargo",
        "curl", "wget", "docker", "kubectl",
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        command = parameters.get("command", "")
        timeout = parameters.get("timeout", 30)

        if not command:
            return ToolOutput(success=False, result=None, error="命令不能为空")

        # 安全检查
        cmd_parts = command.strip().split()
        if not cmd_parts:
            return ToolOutput(success=False, result=None, error="命令为空")

        # 检查第一个命令是否在允许列表中
        base_cmd = cmd_parts[0].lower()
        if base_cmd not in self.ALLOWED_COMMANDS:
            return ToolOutput(
                success=False,
                result=None,
                error=f"命令 '{base_cmd}' 不在允许列表中"
            )

        try:
            result = subprocess.run(
                command,
                shell=True,
                capture_output=True,
                text=True,
                timeout=timeout
            )

            output = result.stdout or result.stderr
            if not output:
                output = "(命令执行成功，无输出)"

            return ToolOutput(
                success=result.returncode == 0,
                result=output,
                metadata={
                    "returncode": result.returncode,
                    "command": command
                }
            )

        except subprocess.TimeoutExpired:
            return ToolOutput(success=False, result=None, error=f"命令超时（{timeout}秒）")
        except Exception as e:
            return ToolOutput(success=False, result=None, error=f"执行失败: {str(e)}")


# ============================================================================
# 动态工具创建工具
# ============================================================================


class CreateToolTool(BaseTool):
    """动态创建新工具

    当现有工具无法满足需求时，可以使用此工具创建新的自定义工具。
    Agent 会自动生成符合规范的 Python 代码，保存到本地插件目录，并热加载到当前会话。
    """

    name = "create_tool"
    description = "动态创建新的自定义工具。当现有工具无法满足需求时，使用此工具创建新的工具。工具会保存到本地插件目录并自动加载到 Agent 中。"
    category = "general"

    input_schema = {
        "type": "object",
        "properties": {
            "tool_name": {
                "type": "string",
                "description": "新工具的名称，使用英文小写字母、数字和下划线，如 'my_tool'"
            },
            "description": {
                "type": "string",
                "description": "工具的功能描述，用于 AI 理解工具用途"
            },
            "input_schema": {
                "type": "object",
                "description": "工具输入参数的 JSON Schema 定义",
                "default": {}
            },
            "code": {
                "type": "string",
                "description": "工具实现代码（execute 方法的返回值语句）。格式：直接写 return 语句，如 'return ToolOutput(success=True, result=f\"Hello, {parameters.get(\"name\")}!\", metadata={})'。注意：只需提供 return 语句，不需要def"
            },
            "category": {
                "type": "string",
                "description": "工具分类，如 'general'、'search'、'file'、'network' 等",
                "default": "general"
            }
        },
        "required": ["tool_name", "description"]
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        tool_name = parameters.get("tool_name", "").strip()
        description = parameters.get("description", "").strip()
        input_schema = parameters.get("input_schema", {})
        code = parameters.get("code", "")
        category = parameters.get("category", "general")

        # 验证参数
        if not tool_name:
            return ToolOutput(success=False, result=None, error="工具名称不能为空")

        if not description:
            return ToolOutput(success=False, result=None, error="工具描述不能为空")

        # 验证工具名称格式
        if not tool_name.replace("_", "").replace("-", "").isalnum():
            return ToolOutput(
                success=False,
                result=None,
                error="工具名称只能包含英文字母、数字、下划线和连字符"
            )

        # 验证 input_schema
        if not isinstance(input_schema, dict):
            input_schema = {}

        try:
            # 导入 ToolLoader
            from .loader import get_tool_loader
            loader = get_tool_loader()

            # 调用 generate_tool
            result = loader.generate_tool(
                name=tool_name,
                description=description,
                input_schema=input_schema,
                category=category,
                code=code if code else None,
                validate=True,
                auto_load=True
            )

            if result.success:
                # 刷新 Agent 的工具列表，让新工具立即可用
                try:
                    from ..agent import _global_agent
                    if _global_agent is not None:
                        _global_agent.refresh_tools()
                        logger.debug(f"[CreateToolTool] 已刷新 Agent 工具列表")
                except Exception:
                    pass

                return ToolOutput(
                    success=True,
                    result=f"工具 '{tool_name}' 创建成功！\n{result.result}\n\n工具已自动刷新到 Agent 中，请直接调用 '{tool_name}' 工具来测试使用。",
                    metadata=result.metadata
                )
            else:
                return ToolOutput(success=False, result=None, error=result.error)

        except Exception as e:
            logger.error(f"[CreateToolTool] 创建工具失败: {e}")
            return ToolOutput(success=False, result=None, error=f"创建工具失败: {str(e)}")


class ListPluginsTool(BaseTool):
    """列出已安装的插件工具"""

    name = "list_plugins"
    description = "列出所有已安装的自定义插件工具。显示插件名称、描述和分类。"
    category = "general"

    input_schema = {
        "type": "object",
        "properties": {}
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        try:
            from .plugin_manager import get_plugin_manager
            plugin_manager = get_plugin_manager()

            plugins = plugin_manager.list_plugins()

            if not plugins:
                return ToolOutput(
                    success=True,
                    result="尚未安装任何自定义插件",
                    metadata={"count": 0}
                )

            lines = []
            for p in plugins:
                lines.append(f"- {p.name}: {p.description} (分类: {p.category}, 版本: {p.version})")

            return ToolOutput(
                success=True,
                result="\n".join(lines),
                metadata={"count": len(plugins)}
            )

        except Exception as e:
            logger.error(f"[ListPluginsTool] 列出插件失败: {e}")
            return ToolOutput(success=False, result=None, error=str(e))


class DeletePluginTool(BaseTool):
    """删除自定义插件工具"""

    name = "delete_plugin"
    description = "删除指定的自定义插件工具。删除后该工具将不可用。"
    category = "general"

    input_schema = {
        "type": "object",
        "properties": {
            "tool_name": {
                "type": "string",
                "description": "要删除的工具名称"
            }
        },
        "required": ["tool_name"]
    }

    def execute(self, parameters: Dict[str, Any], context: Optional[Dict] = None) -> ToolOutput:
        tool_name = parameters.get("tool_name", "").strip()

        if not tool_name:
            return ToolOutput(success=False, result=None, error="工具名称不能为空")

        try:
            from .plugin_manager import get_plugin_manager
            plugin_manager = get_plugin_manager()

            # 验证插件是否存在
            if not (plugin_manager.plugin_dir / tool_name / "__init__.py").exists():
                return ToolOutput(success=False, result=None, error=f"插件不存在: {tool_name}")

            # 删除插件
            success = plugin_manager.delete_plugin(tool_name)

            if success:
                return ToolOutput(
                    success=True,
                    result=f"插件 '{tool_name}' 已删除",
                    metadata={"name": tool_name}
                )
            else:
                return ToolOutput(success=False, result=None, error="删除失败")

        except Exception as e:
            logger.error(f"[DeletePluginTool] 删除插件失败: {e}")
            return ToolOutput(success=False, result=None, error=str(e))
