"""Naming helpers for MCP tool registration."""

from __future__ import annotations

import asyncio
import functools
import json
import logging
import time
from typing import Any, Callable

from mcp.server.fastmcp import FastMCP
from mcp.types import TextContent

from foundry_mcp.core.observability import mcp_tool

logger = logging.getLogger(__name__)


def _minify_response(result: dict[str, Any]) -> TextContent:
    """Convert dict to TextContent with minified JSON.

    Args:
        result: Dictionary to serialize

    Returns:
        TextContent with minified JSON string
    """
    return TextContent(
        type="text",
        text=json.dumps(result, separators=(",", ":"), default=str),
    )


def canonical_tool(
    mcp: FastMCP,
    *,
    canonical_name: str,
    **tool_kwargs: Any,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    """Decorator that registers a tool under its canonical name.

    This decorator wraps the tool function to:
    1. Register it with FastMCP under the canonical name
    2. Apply observability instrumentation via mcp_tool
    3. Collect error data when exceptions occur

    Args:
        mcp: FastMCP instance
        canonical_name: The canonical name for the tool
        **tool_kwargs: Additional kwargs passed to mcp.tool()

    Returns:
        Decorated function registered as an MCP tool
    """

    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        if asyncio.iscoroutinefunction(func):
            # Async function - use async wrapper
            @functools.wraps(func)
            async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
                """Async wrapper for async underlying functions."""
                start_time = time.perf_counter()
                try:
                    result = await func(*args, **kwargs)
                    if isinstance(result, dict):
                        return _minify_response(result)
                    return result
                except Exception as e:
                    duration_ms = (time.perf_counter() - start_time) * 1000
                    _collect_tool_error(
                        tool_name=canonical_name,
                        error=e,
                        input_params=kwargs,
                        duration_ms=duration_ms,
                    )
                    raise

            wrapper = async_wrapper
        else:
            # Sync function - use sync wrapper to preserve sync behavior
            @functools.wraps(func)
            def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
                """Sync wrapper for sync underlying functions."""
                start_time = time.perf_counter()
                try:
                    result = func(*args, **kwargs)
                    if isinstance(result, dict):
                        return _minify_response(result)
                    return result
                except Exception as e:
                    duration_ms = (time.perf_counter() - start_time) * 1000
                    _collect_tool_error(
                        tool_name=canonical_name,
                        error=e,
                        input_params=kwargs,
                        duration_ms=duration_ms,
                    )
                    raise

            wrapper = sync_wrapper

        # Apply mcp_tool first, then register with FastMCP
        instrumented = mcp_tool(tool_name=canonical_name)(wrapper)
        return mcp.tool(name=canonical_name, **tool_kwargs)(instrumented)

    return decorator


def _collect_tool_error(
    tool_name: str,
    error: Exception,
    input_params: dict[str, Any],
    duration_ms: float,
) -> None:
    """Collect error data for later introspection.

    Uses lazy import to avoid circular dependencies and only
    collects if error collection is enabled.

    Args:
        tool_name: Name of the tool that raised the error
        error: The exception that was raised
        input_params: Input parameters passed to the tool
        duration_ms: Duration in milliseconds before error
    """
    try:
        # Lazy import to avoid circular dependencies
        from foundry_mcp.config.server import get_config

        config = get_config()
        if not config.error_collection.enabled:
            return

        from foundry_mcp.core.error_collection import get_error_collector

        collector = get_error_collector()
        collector.collect_tool_error(
            tool_name=tool_name,
            error=error,
            input_params=input_params,
            duration_ms=duration_ms,
        )
    except Exception as collect_error:
        # Never let error collection failures affect tool execution
        logger.debug(f"Error collection failed for {tool_name}: {collect_error}")
