"""Beaver 工具注册表。

这层只做三件事：
1. 注册工具
2. 按名称查找工具
3. 导出 provider 可消费的 tool schemas

不要把执行逻辑塞进这里。
执行属于 runtime/executor，那样边界更清晰。
"""

from __future__ import annotations

from collections.abc import Sequence
from typing import Iterable

from beaver.tools.base import BaseTool, ToolSpec


class ToolRegistry:
    """统一维护当前 runtime 可用的工具集合。"""

    def __init__(self) -> None:
        self._tools: dict[str, BaseTool] = {}

    def register(self, tool: BaseTool, *, replace: bool = False) -> None:
        """注册一个工具。

        默认不允许重名覆盖，避免 loader/runtime 不小心把同名工具静默冲掉。
        """

        name = tool.spec.name
        if not replace and name in self._tools:
            raise ValueError(f"Tool '{name}' is already registered")
        self._tools[name] = tool

    def register_many(self, tools: Iterable[BaseTool], *, replace: bool = False) -> None:
        for tool in tools:
            self.register(tool, replace=replace)

    def get(self, name: str) -> BaseTool | None:
        return self._tools.get(name)

    def require(self, name: str) -> BaseTool:
        tool = self.get(name)
        if tool is None:
            raise KeyError(f"Unknown tool '{name}'")
        return tool

    def list_specs(self) -> list[ToolSpec]:
        return [tool.spec for tool in self._tools.values()]

    def list_always_specs(self) -> list[ToolSpec]:
        """列出每轮 run 都应该暴露给模型的基础工具。"""

        return [spec for spec in self.list_specs() if spec.always_available]

    def get_specs(self, names: Sequence[str]) -> list[ToolSpec]:
        """按名称顺序返回已注册工具 spec，忽略未知工具。"""

        specs: list[ToolSpec] = []
        seen: set[str] = set()
        for name in names:
            tool = self.get(name)
            if tool is None or name in seen:
                continue
            specs.append(tool.spec)
            seen.add(name)
        return specs

    def export_provider_schemas(self) -> list[dict]:
        """导出给 provider 的函数工具 schema 列表。"""

        return [spec.to_provider_schema() for spec in self.list_specs()]

    def export_selected_provider_schemas(self, specs: Sequence[ToolSpec]) -> list[dict]:
        """导出一组已选择工具的 provider schema。"""

        return [spec.to_provider_schema() for spec in specs]
