import json

from fastapi import APIRouter, HTTPException

from backend.config import (
    GOOGLE_API_SUPPORT,
    OUTLOOK_SUPPORT,
    TOOLS_DIR,
    _google_get_credentials,
    _BUILTIN_TOOL_NAMES,
    _PROMOTED_CUSTOM_BUILTIN_NAMES,
    _load_settings,
    _normalize_tool_enabled_map,
    _normalize_tool_name,
)
from backend.mcp_runtime import _mcp_get_cache
from backend.tool_catalog import build_runtime_tool_catalog
from backend.tool_registry_runtime import _dynamic_tools, _reload_dynamic_tools


router = APIRouter()


def _settings_outlook_enabled(settings: dict | None) -> bool:
    source = settings or {}
    if "use_outlook" in source:
        return bool(source.get("use_outlook", False))
    return bool(source.get("outlook_enabled", False))


def _build_runtime_tool_entries() -> list[dict]:
    settings = _load_settings()
    use_outlook = bool(_settings_outlook_enabled(settings) and OUTLOOK_SUPPORT)
    gmail_available = bool(settings.get("google_enabled", False)) and GOOGLE_API_SUPPORT and (_google_get_credentials() is not None)
    catalog = build_runtime_tool_catalog(
        settings,
        dynamic_tools=_dynamic_tools,
        mcp_cache=_mcp_get_cache(),
        use_outlook=use_outlook,
        gmail_available=gmail_available,
    )
    entries: list[dict] = []
    for name, capability in sorted(catalog.items()):
        entries.append({
            "name": name,
            "description": str(getattr(capability, "description", "") or "").strip(),
            "enabled": bool(getattr(capability, "enabled", False)),
            "available": bool(getattr(capability, "available", False)),
            "source": str(getattr(capability, "source", "") or ""),
            "category": str(getattr(capability, "category", "") or ""),
            "domains": list(getattr(capability, "domains", []) or []),
            "side_effect": bool(getattr(capability, "side_effect", False)),
            "requires_approval": bool(getattr(capability, "requires_approval", False)),
            "args": dict(getattr(capability, "input_schema", {}) or {}),
            "metadata": dict(getattr(capability, "metadata", {}) or {}),
        })
    return entries


@router.get("/api/tools/runtime")
def api_list_runtime_tools():
    """Return the full runtime capability catalog used by chat and planning."""
    return {"tools": _build_runtime_tool_entries()}


@router.get("/api/tools")
def api_list_tools():
    """List runtime custom tools from the shared capability catalog."""
    return {
        "tools": [
            tool
            for tool in _build_runtime_tool_entries()
            if str(tool.get("source") or "") == "custom"
        ]
    }


@router.get("/api/tools/builtin")
def api_list_builtin_tools():
    """Return builtin tools from tools/_builtin.json, merged with promoted dynamic tools."""
    builtin_file = TOOLS_DIR / "_builtin.json"
    if not builtin_file.exists():
        return {"tools": []}
    try:
        tools = json.loads(builtin_file.read_text(encoding="utf-8"))
        tool_map = _normalize_tool_enabled_map(_load_settings().get("tool_enabled_map"))
        known = {
            _normalize_tool_name(str(t.get("name", "")).strip())
            for t in tools
            if isinstance(t, dict)
        }
        for name in sorted(_PROMOTED_CUSTOM_BUILTIN_NAMES):
            normalized = _normalize_tool_name(name)
            tool = _dynamic_tools.get(normalized)
            if not tool or normalized in known:
                continue
            tools.append({
                "name": normalized,
                "description": tool.get("description", "Built-in tool."),
                "args": tool.get("args_desc", "{}"),
            })
        out_by_name: dict[str, dict] = {}
        for tool in tools:
            name = _normalize_tool_name(str(tool.get("name", "")))
            if not name:
                continue
            out_by_name[name] = {
                **tool,
                "name": name,
                "enabled": bool(tool_map.get(name, True)),
            }
        return {"tools": list(out_by_name.values())}
    except Exception as exc:
        return {"tools": [], "error": str(exc)}


@router.get("/api/tools/mcp")
def api_list_mcp_tools():
    """Return MCP-discovered capabilities from the shared runtime capability catalog."""
    return {
        "tools": [
            tool
            for tool in _build_runtime_tool_entries()
            if str(tool.get("source") or "").startswith("mcp")
        ]
    }


@router.delete("/api/tools/{tool_name}")
def api_delete_tool(tool_name: str):
    """Remove a custom tool by name and reload the registry."""
    if tool_name in _PROMOTED_CUSTOM_BUILTIN_NAMES:
        raise HTTPException(
            status_code=403,
            detail=(
                f"Skill '{tool_name}' is promoted to built-in and cannot be deleted. "
                "Disable it in Settings > Skills if needed."
            ),
        )
    tool = _dynamic_tools.get(tool_name)
    if not tool:
        raise HTTPException(status_code=404, detail="Tool not found")
    tool["file"].unlink(missing_ok=True)
    _reload_dynamic_tools()
    return {"ok": True}


@router.get("/api/tools/{tool_name}/source")
def api_tool_source(tool_name: str):
    """Return the source code of a custom tool."""
    tool = _dynamic_tools.get(tool_name)
    if not tool:
        raise HTTPException(status_code=404, detail="Tool not found")
    return {
        "name": tool_name,
        "description": tool.get("description", ""),
        "args": tool.get("args_desc", "{}"),
        "source": tool.get("source", ""),
    }