"""Tool profile: compute which tools are visible to the LLM for a given config profile."""

from __future__ import annotations

from typing import TYPE_CHECKING

from loguru import logger

from nanobot.config.schema import ToolProfileConfig

if TYPE_CHECKING:
    from nanobot.agent.tools.registry import ToolRegistry


def mcp_server_for_tool(tool_name: str, mcp_server_keys: list[str]) -> str | None:
    """
    Infer MCP server config key from nanobot's tool name pattern mcp_<serverKey>_<mcpToolName>.

    Server keys are matched longest-first so names with underscores resolve unambiguously.
    """
    prefix = "mcp_"
    if not tool_name.startswith(prefix):
        return None
    rest = tool_name[len(prefix) :]
    for key in sorted(mcp_server_keys, key=len, reverse=True):
        sep = f"{key}_"
        if rest.startswith(sep):
            return key
    return None


def mcp_keys_to_connect(
    profile: ToolProfileConfig, configured_mcp_keys: list[str]
) -> list[str]:
    """
    Config keys for MCP servers to connect for this profile, in config order.

    None on profile.mcp_servers means all configured servers; [] means none.
    Unknown keys in the profile list are logged and skipped.
    """
    if not configured_mcp_keys:
        return []
    configured_set = set(configured_mcp_keys)
    if profile.mcp_servers is None:
        return list(configured_mcp_keys)
    out: list[str] = []
    for k in profile.mcp_servers:
        if k in configured_set:
            out.append(k)
        else:
            logger.warning(
                f"tools.toolProfiles entry references unknown MCP server {k!r}; "
                "not in tools.mcpServers keys"
            )
    return out


def compute_allowed_tool_names(
    registry: ToolRegistry,
    profile: ToolProfileConfig,
    mcp_server_keys: list[str],
    always_include: set[str],
) -> set[str]:
    """Union of profile-filtered builtins + MCP tools + always-include (intersected with registered names)."""
    all_names = set(registry.tool_names)
    mcp_keys = list(mcp_server_keys)

    builtins = {n for n in all_names if mcp_server_for_tool(n, mcp_keys) is None}

    if profile.builtin_tools is None:
        allowed_builtins = set(builtins)
    else:
        allowed_builtins = set(profile.builtin_tools) & builtins

    if profile.mcp_servers is None:
        allowed_mcp = {
            n for n in all_names if mcp_server_for_tool(n, mcp_keys) is not None
        }
    else:
        allow_srv = set(profile.mcp_servers)
        allowed_mcp = {
            n
            for n in all_names
            if (srv := mcp_server_for_tool(n, mcp_keys)) is not None and srv in allow_srv
        }

    extras = always_include & all_names
    return allowed_builtins | allowed_mcp | extras
