"""LLM-based router: choose a tools.toolProfiles key from the user message."""

from __future__ import annotations

import json_repair
from loguru import logger

from nanobot.config.schema import ToolProfileConfig
from nanobot.providers.base import LLMProvider


async def route_tool_profile(
    provider: LLMProvider,
    *,
    model: str,
    user_message: str,
    profiles: dict[str, ToolProfileConfig],
    default_profile: str,
    temperature: float = 0.2,
    max_tokens: int = 128,
) -> str:
    """
    Ask a small LLM call to return JSON {"profile": "<key>"}.

    Falls back to default_profile on any failure or unknown key.
    """
    if not profiles:
        return default_profile

    # Heuristic fast-path: if the request clearly needs a dev/forge MCP (PRs, issues, repos),
    # prefer an MCP-enabled profile without spending an LLM call.
    msg_l = (user_message or "").lower()
    needs_forge = any(
        k in msg_l
        for k in [
            "pull request",
            "pull requests",
            "open pr",
            "open prs",
            " list prs",
            "pr ",
            "prs",
            "merge request",
            "issue",
            "issues",
            "gitea",
            "repo",
            "repository",
            "branches",
            "commits",
            "tags",
            "release",
        ]
    )
    if needs_forge:
        # Prefer an explicit "*mcp*" profile key if present, else any profile that enables MCP servers.
        for key in profiles.keys():
            if "mcp" in key.lower():
                logger.info(f"Tool router selected profile '{key}' (heuristic)")
                return key
        for key, p in profiles.items():
            if p.mcp_servers is None or (isinstance(p.mcp_servers, list) and len(p.mcp_servers) > 0):
                logger.info(f"Tool router selected profile '{key}' (heuristic)")
                return key

    lines = []
    for name, p in profiles.items():
        desc = (p.description or "").strip() or "(no description)"
        lines.append(f"- {name}: {desc}")
    catalog = "\n".join(lines)
    allowed = ", ".join(f'"{k}"' for k in profiles)

    system = (
        "You are a tool-profile router. Pick exactly one profile key for the assistant's next turn. "
        "Respond with JSON only: {\"profile\": \"<key>\"} where <key> is one of: "
        f"{allowed}. "
        "Prefer narrower profiles when the request is clearly scoped (e.g. only read files). "
        "Use the broadest profile only when multiple unrelated capabilities are needed."
    )
    user = f"Available profiles:\n{catalog}\n\nUser message:\n{user_message.strip()[:8000]}"

    try:
        response = await provider.chat(
            messages=[
                {"role": "system", "content": system},
                {"role": "user", "content": user},
            ],
            tools=None,
            model=model,
            temperature=temperature,
            max_tokens=max_tokens,
        )
        text = (response.content or "").strip()
        if not text:
            return default_profile
        if text.startswith("```"):
            text = text.split("\n", 1)[-1].rsplit("```", 1)[0].strip()
        data = json_repair.loads(text)
        if not isinstance(data, dict):
            return default_profile
        name = data.get("profile")
        if isinstance(name, str) and name in profiles:
            logger.info(f"Tool router selected profile '{name}'")
            return name
        logger.warning(f"Tool router returned invalid profile {name!r}, using default")
    except (TypeError, ValueError) as e:
        logger.warning(f"Tool router JSON parse failed: {e}")
    except Exception as e:
        logger.warning(f"Tool router failed: {e}")

    return default_profile


def is_tool_not_found_error(result: str) -> bool:
    """Detect registry execute() message for missing tools."""
    if not result:
        return False
    return result.startswith("Error: Tool '") and "' not found" in result
