"""内置工具 - 开箱即用的常用工具集合"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING, Any

from agentkit.tools.base import Tool

if TYPE_CHECKING:
    from agentkit.tools.search import ToolSearchIndex

logger = logging.getLogger(__name__)


class RunTestsTool(Tool):
    """运行项目测试验证代码变更

    执行 pytest 和 linting 命令来验证代码变更的正确性。
    内部使用 VerificationLoop 实现验证逻辑。
    """

    def __init__(
        self,
        name: str = "run_tests",
        description: str = "Run project tests to verify code changes. Executes pytest and linting commands.",
        input_schema: dict[str, Any] | None = None,
        output_schema: dict[str, Any] | None = None,
        version: str = "1.0.0",
        tags: list[str] | None = None,
        working_dir: str | None = None,
        timeout: float = 60.0,
        max_retries: int = 0,
    ):
        super().__init__(
            name=name,
            description=description,
            input_schema=input_schema or self._default_input_schema(),
            output_schema=output_schema,
            version=version,
            tags=tags or ["testing", "verification"],
        )
        self._working_dir = working_dir
        self._timeout = timeout
        self._max_retries = max_retries

    @staticmethod
    def _default_input_schema() -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {
                "commands": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Shell commands to run for verification. Default: ['pytest -x -q', 'ruff check src/']",
                },
            },
        }

    async def execute(self, **kwargs) -> dict:
        """执行测试验证

        Args:
            commands: 可选的验证命令列表，默认使用 pytest 和 ruff check。

        Returns:
            包含 passed, attempts, test_output, errors 的字典。
        """
        from agentkit.core.verification_loop import VerificationLoop

        commands: list[str] | None = kwargs.get("commands")
        loop = VerificationLoop(
            commands=commands,
            max_retries=self._max_retries,
            working_dir=self._working_dir,
            timeout=self._timeout,
        )
        result = await loop.verify()
        return {
            "passed": result.passed,
            "attempts": result.attempts,
            "test_output": result.test_output,
            "errors": result.errors,
        }


class ToolSearchTool(Tool):
    """工具搜索工具

    让 Agent 可以通过关键词搜索扩展工具的完整描述。配合工具描述分层注入使用：
    核心工具全量注入 prompt，扩展工具只注入名称+一行描述，Agent 通过此工具
    按需获取扩展工具的完整参数说明。

    底层使用 :class:`ToolSearchIndex`（BM25 算法）进行关键词匹配搜索。

    Usage::

        from agentkit.tools.search import ToolSearchIndex
        from agentkit.tools.builtin import ToolSearchTool

        index = ToolSearchIndex(extended_tools)
        tool = ToolSearchTool(search_index=index)
        result = await tool.execute(query="read file")
    """

    def __init__(
        self,
        search_index: "ToolSearchIndex",
        name: str = "tool_search",
        description: str = (
            "Search for available tools by keyword. "
            "Returns full descriptions (name, description, parameters) of matching tools. "
            "Use this when you need details about a tool that was only listed by name."
        ),
        input_schema: dict[str, Any] | None = None,
        output_schema: dict[str, Any] | None = None,
        version: str = "1.0.0",
        tags: list[str] | None = None,
        top_k: int = 5,
    ):
        if top_k < 1:
            raise ValueError(f"top_k must be >= 1, got {top_k}")
        schema = input_schema or {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": (
                        "Search keywords to find relevant tools "
                        "(e.g. 'read file', 'web search', 'run tests')."
                    ),
                },
            },
            "required": ["query"],
        }
        super().__init__(
            name=name,
            description=description,
            input_schema=schema,
            output_schema=output_schema,
            version=version,
            tags=tags or ["tool", "search", "meta"],
        )
        self._search_index = search_index
        self._top_k = top_k

    async def execute(self, **kwargs) -> dict:
        """执行工具搜索。

        Args:
            query: 搜索关键词。

        Returns:
            包含 ``query``、``count`` 和 ``results``（每个工具的完整描述）的字典。
        """
        query = str(kwargs.get("query", "")).strip()
        if not query:
            return {
                "error": "query parameter is required",
                "results": [],
            }

        results = self._search_index.search(query, top_k=self._top_k)
        if not results:
            return {
                "query": query,
                "count": 0,
                "results": [],
                "message": f"No tools matched '{query}'.",
            }

        return {
            "query": query,
            "count": len(results),
            "results": [self._format_tool_full(tool) for tool in results],
        }

    @staticmethod
    def _format_tool_full(tool: Tool) -> dict[str, Any]:
        """Format a tool's full description for the LLM."""
        return {
            "name": tool.name,
            "description": tool.description,
            "parameters": tool.input_schema or {"type": "object", "properties": {}},
        }
