from typing import Dict, List, Optional, Any, Callable

from .base import BaseTool
from .filesystem import ReadTool, WriteTool, EditTool, GlobTool, GrepTool
from .system import BashTool
from .todo_tool import TodoWriteTool, TodoReadTool
from .skill_tool import SkillTool
from .agent_tool import PlanEnterTool, PlanExitTool
from .web_tools import WebSearchTool, WebFetchTool
from .codesearch_tool import CodeSearchTool
from .lsp_tool import LspTool
from .clarify_tool import ClarifyTool
from lsp.server import get_available_servers
from core.interaction import get_interaction_manager


# 工具分类定义 - 仅展示白名单中的分类
TOOL_CATEGORIES = {
    "filesystem": {
        "name": "文件系统",
        "tools": ["read", "write", "edit", "glob", "grep"],
    },
    "web": {
        "name": "Web 搜索",
        "tools": ["websearch", "webfetch", "codesearch"],
    },
    "system": {
        "name": "系统工具",
        "tools": ["bash"],
    },
    "mcp": {
        "name": "用户定制 (MCP)",
        "tools": [],  # 动态添加
    },
}


class ToolRegistry:
    """工具注册中心 - 统一管理所有可用工具"""

    def __init__(
        self,
        session_id: Optional[str] = None,
        agent_manager: Optional[Any] = None,
        interaction_manager: Optional[Any] = None,
        mcp_tools_getter: Optional[Callable[[], List["BaseTool"]]] = None,
    ):
        """
        初始化工具注册表

        Args:
            session_id: 会话 ID
            agent_manager: Agent 管理器
            interaction_manager: 交互管理器
            mcp_tools_getter: MCP 工具获取函数（动态获取最新工具）
        """
        from .base import BaseTool

        self._tools: Dict[str, BaseTool] = {}
        self._session_id = session_id
        self._agent_manager = agent_manager
        self._interaction_manager = interaction_manager
        self._mcp_tools_getter = mcp_tools_getter
        self._register_defaults()

    def _register_defaults(self):
        self.register(ReadTool())
        self.register(WriteTool())
        self.register(EditTool())
        self.register(GlobTool())
        self.register(GrepTool())
        self.register(BashTool())
        self.register(SkillTool())

        self.register(WebSearchTool())
        self.register(WebFetchTool())
        self.register(CodeSearchTool())

        # 只有当有可用的语言服务器时才注册 LSP 工具
        available_servers = get_available_servers()
        if available_servers:
            self.register(LspTool())

        # Register todo tools if session_id is provided
        if self._session_id:
            self.register(TodoWriteTool(self._session_id))
            self.register(TodoReadTool(self._session_id))
            self.register(ClarifyTool(self._session_id, self._interaction_manager))

        # Register agent tools if agent_manager is provided
        if self._agent_manager:
            self.register(PlanEnterTool(self._agent_manager))
            self.register(PlanExitTool(self._agent_manager))

        # Register MCP tools (if available)
        self._refresh_mcp_tools()

    def register(self, tool: BaseTool):
        self._tools[tool.name] = tool

    def register_batch(self, tools: List[BaseTool]):
        for tool in tools:
            self.register(tool)

    def _refresh_mcp_tools(self) -> None:
        """刷新 MCP 工具（动态获取最新工具）"""
        if not self._mcp_tools_getter:
            return

        try:
            mcp_tools = self._mcp_tools_getter() or []
        except Exception:
            # MCP 工具获取失败时不影响其他工具使用
            return

        for tool in mcp_tools:
            if tool.name not in self._tools:
                self._tools[tool.name] = tool

    def get_tool(self, name: str) -> Optional[BaseTool]:
        self._refresh_mcp_tools()
        return self._tools.get(name)

    def get_all_tools(self) -> list[BaseTool]:
        self._refresh_mcp_tools()
        return list(self._tools.values())

    def get_openai_tools(self) -> list[dict]:
        self._refresh_mcp_tools()
        return [tool.schema for tool in self._tools.values()]

    def get_tools_by_category(
        self,
        allowed_tool_names: Optional[set] = None,
    ) -> Dict[str, List[Dict[str, str]]]:
        """获取按分类组织的工具列表（仅返回白名单中的分类）

        Args:
            allowed_tool_names: 可选的允许工具名称集合，如果提供则只返回这些工具

        Returns:
            Dict[str, List[Dict[str, str]]]: {category_key: [{"name": ..., "description": ...}, ...]}
        """
        self._refresh_mcp_tools()

        # 获取 MCP 工具名称集合
        mcp_tool_names = set()
        if self._mcp_tools_getter:
            try:
                mcp_tools = self._mcp_tools_getter() or []
                mcp_tool_names = {t.name for t in mcp_tools}
            except Exception:
                pass

        # 构建结果字典
        result: Dict[str, List[Dict[str, str]]] = {}

        for tool in self._tools.values():
            # 如果指定了允许列表，跳过不在列表中的工具
            if allowed_tool_names is not None and tool.name not in allowed_tool_names:
                continue

            # 判断工具属于哪个分类
            categorized = False

            # 优先检查是否是 MCP 工具
            if tool.name in mcp_tool_names:
                if "mcp" not in result:
                    result["mcp"] = []
                result["mcp"].append({
                    "name": tool.name,
                    "description": tool.description,
                })
                continue

            # 检查是否在预定义的分类中
            for cat_key, cat_info in TOOL_CATEGORIES.items():
                if tool.name in cat_info["tools"]:
                    if cat_key not in result:
                        result[cat_key] = []
                    result[cat_key].append({
                        "name": tool.name,
                        "description": tool.description,
                    })
                    categorized = True
                    break

        # 只返回白名单中的分类（即使为空也保留，用于展示）
        for cat_key in TOOL_CATEGORIES:
            if cat_key not in result:
                result[cat_key] = []

        return result
