from __future__ import annotations

import time
from collections.abc import Callable
from typing import TYPE_CHECKING, Any

from niannian.external_data.capability import CapabilityDeniedError
from niannian.mcp.audit import write_audit

if TYPE_CHECKING:
    from niannian.mcp.service import NianNianService


def raise_capability_denied(exc: CapabilityDeniedError) -> None:
    from mcp.server.fastmcp.exceptions import ToolError

    raise ToolError(f"403 Forbidden: {exc.reason}") from exc


def run_inbound_tool(
    svc: NianNianService,
    *,
    tool: str,
    args_summary: str,
    capability_id: str | None,
    fn: Callable[[], Any],
) -> Any:
    """MCP 入站工具：写 direction=in 审计，CapabilityDeniedError → 403 ToolError。"""
    t0 = time.monotonic()
    try:
        result = fn()
    except CapabilityDeniedError as exc:
        write_audit(
            home=svc.home,
            config=svc._config,
            direction="in",
            tool=tool,
            args_summary=args_summary,
            capability_id=capability_id,
            ok=False,
            duration_ms=int((time.monotonic() - t0) * 1000),
            error=str(exc),
        )
        raise_capability_denied(exc)
    except Exception as exc:
        write_audit(
            home=svc.home,
            config=svc._config,
            direction="in",
            tool=tool,
            args_summary=args_summary,
            capability_id=capability_id,
            ok=False,
            duration_ms=int((time.monotonic() - t0) * 1000),
            error=str(exc),
        )
        raise
    write_audit(
        home=svc.home,
        config=svc._config,
        direction="in",
        tool=tool,
        args_summary=args_summary,
        capability_id=capability_id,
        ok=True,
        duration_ms=int((time.monotonic() - t0) * 1000),
    )
    return result
