"""Langfuse observability integration for FastMCP v3 servers.

Two complementary APIs:

- ``instrument(mcp)`` -- one call, zero per-handler code.
- ``@langfuse_trace`` -- opt-in decorator for fine-grained control.

Quick start::

    from langfuse import get_client
    get_client()                              # init Langfuse OTel provider

    from fastmcp import FastMCP
    from fastmcp_langfuse import instrument

    mcp = FastMCP("My Server")
    instrument(mcp)                           # <-- one line

    @mcp.tool()
    def anything(x: str) -> str:              # fully traced
        return "hello"
"""

from __future__ import annotations

from typing import Any

from ._core import F, _patch_registration, _wrap_handler
from .config import LangfuseConfig

__all__ = ["instrument", "langfuse_trace", "LangfuseConfig"]


_default_config = LangfuseConfig()


def langfuse_trace(fn: F) -> F:
    """Decorator that auto-enriches a single handler with Langfuse tracing.

    Uses the default ``LangfuseConfig()`` unless ``instrument()`` has been
    called, in which case the config passed there is used.

    Example::

        @mcp.tool()
        @langfuse_trace
        def my_tool(x: str) -> str:
            return "hello"
    """
    return _wrap_handler(fn, _default_config)


def instrument(
    mcp: Any,
    *,
    config: LangfuseConfig | None = None,
    environment: str = "",
    release: str = "",
    session_tracking: bool = True,
    trace_urls: bool = True,
    base_url: str = "https://cloud.langfuse.com",
) -> None:
    """Patch ``mcp.tool()``, ``mcp.resource()``, ``mcp.prompt()`` so every
    registered handler is automatically wrapped with Langfuse enrichment
    and I/O capture.

    Call **once**, right after creating the ``FastMCP`` instance.

    You can pass a ``LangfuseConfig`` object, or use keyword arguments
    (keyword arguments are ignored when ``config`` is provided)::

        # Option A: keyword arguments
        instrument(mcp, environment="production", trace_urls=False)

        # Option B: config object
        instrument(mcp, config=LangfuseConfig(environment="production"))

    Args:
        mcp: The ``FastMCP`` server instance.
        config: A ``LangfuseConfig`` with all settings.  If not provided,
                one is built from the keyword arguments.
        environment: ``langfuse.environment`` span attribute.
        release: ``langfuse.release`` span attribute.
        session_tracking: Set session/user IDs from FastMCP context.
        trace_urls: Print Langfuse trace URLs to console.
        base_url: Langfuse instance URL (for building trace links).
    """
    global _default_config

    if config is None:
        config = LangfuseConfig(
            environment=environment,
            release=release,
            session_tracking=session_tracking,
            trace_urls=trace_urls,
            base_url=base_url,
        )

    # Update module-level default so @langfuse_trace picks it up too.
    _default_config = config

    for method_name in ("tool", "resource", "prompt"):
        _patch_registration(mcp, method_name, config)
