# File: src/noveler/presentation/mcp/tool_registry.py
# Purpose: Presentation-layer access to the MCP tool registry.
# Context: Provides a stable API to obtain the list of MCP tools while the
#          legacy server code remains in mcp_servers/noveler/main.py.
"""Presentation-layer MCP tool registry facade.

This module exposes a small API to retrieve the list of MCP tools. Internally
it defers to the current server implementation to avoid duplication during the
transition to a cleaner architecture.
"""

from __future__ import annotations

import asyncio
import sys
import warnings
from contextvars import ContextVar

from mcp import Tool

_legacy_guard: ContextVar[bool] = ContextVar("_legacy_tool_registry_guard", default=False)


def _build_stub_tools() -> list[Tool]:
    """Fallback helper that synthesises minimal Tool objects from dispatcher data."""

    from noveler.presentation.mcp.dispatcher import get_registered_tools  # noqa: PLC0415

    minimal_schema = {"type": "object", "properties": {}, "additionalProperties": True}
    return [
        Tool(
            name=name,
            description="Fallback stub (presentation tool definitions unavailable).",
            inputSchema=minimal_schema,
        )
        for name in sorted(get_registered_tools())
    ]


async def _load_from_legacy() -> list[Tool]:
    """Invoke the legacy registry helper while preventing recursive loops."""

    if _legacy_guard.get():
        return []

    legacy_module = sys.modules.get("mcp_servers.noveler.main")
    if legacy_module is None:
        try:
            from mcp_servers.noveler import main as legacy_module  # type: ignore[assignment]  # noqa: PLC0415
        except Exception:
            return []

    getter = getattr(legacy_module, "_legacy_list_tools_impl", None)
    if getter is None:
        return []

    token = _legacy_guard.set(True)
    try:
        return await getter()  # type: ignore[no-any-return]
    finally:
        _legacy_guard.reset(token)


async def get_tools_async() -> list[Tool]:
    """Return the list of MCP tools available to the presentation layer."""

    try:
        from noveler.presentation.mcp import mcp_tool_registry  # noqa: PLC0415

        return await mcp_tool_registry.get_legacy_tools()
    except (ModuleNotFoundError, ImportError):
        warnings.warn(
            "Presentation tool definitions missing; falling back to legacy registry.",
            RuntimeWarning,
            stacklevel=2,
        )
        tools = await _load_from_legacy()
        return tools or _build_stub_tools()
    except Exception:
        tools = await _load_from_legacy()
        if tools:
            return tools
        warnings.warn(
            "Unable to list MCP tools via presentation registry; returning dispatcher stubs.",
            RuntimeWarning,
            stacklevel=2,
        )
        return _build_stub_tools()


def get_tools() -> list[Tool]:
    """Synchronous helper to obtain tools (convenience for callers)."""

    try:
        loop = asyncio.get_running_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()
        try:
            asyncio.set_event_loop(loop)
            return loop.run_until_complete(get_tools_async())
        finally:
            try:
                loop.close()
            except Exception:
                pass
    else:
        return loop.run_until_complete(get_tools_async())  # type: ignore[no-any-return]
