"""MCP Python SDK session configuration emitter.

Generates transport parameters for the MCP Python SDK's ClientSession
with Bearer auth, proper Origin header, and Streamable HTTP transport
semantics.

Two helpers are provided:

- ``mcp_session_params()`` — returns a static dict for a fixed token.
- ``mcp_session_params_factory()`` — returns a zero-arg callable that
  produces fresh params on each call, suitable for refreshable tokens.
"""

from __future__ import annotations

from collections.abc import Callable
from typing import Any

MCP_PROTOCOL_VERSION = "2025-03-26"


def mcp_session_params(
    gateway_url: str,
    token: str,
    *,
    protocol_version: str = MCP_PROTOCOL_VERSION,
    origin: str | None = None,
) -> dict[str, Any]:
    """Generate MCP SDK transport parameters for ARIA MCP Gateway.

    Returns a dict of keyword arguments suitable for constructing an
    MCP SDK Streamable HTTP transport pointing at the ARIA MCP Gateway.

    Args:
        gateway_url: ARIA MCP Gateway URL (e.g. ``https://mcp.example.com/v1/mcp``).
        token: Bearer token for MCP requests.
        protocol_version: MCP protocol version string.
        origin: Origin header value. Required by MCP spec for remote
            Streamable HTTP servers. Defaults to the gateway URL's origin.

    Returns:
        A dict with keys: ``url``, ``headers``, ``transport``.

    Example::

        params = mcp_session_params(
            gateway_url="https://mcp.acme.com/v1/mcp",
            token="eyJ...",
        )
    """
    if not gateway_url:
        raise ValueError("gateway_url must not be empty")
    if not token:
        raise ValueError("token must not be empty")

    return _build_params(gateway_url, token, protocol_version, origin)


def mcp_session_params_factory(
    gateway_url: str,
    token_factory: Callable[[], str],
    *,
    protocol_version: str = MCP_PROTOCOL_VERSION,
    origin: str | None = None,
) -> Callable[[], dict[str, Any]]:
    """Return a zero-arg callable that produces fresh MCP session params.

    Each call invokes ``token_factory()`` to obtain a current Bearer token,
    making this suitable for OAuth client-credentials flows where tokens
    expire and must be refreshed.

    Args:
        gateway_url: ARIA MCP Gateway URL.
        token_factory: Zero-arg callable returning a current Bearer token.
        protocol_version: MCP protocol version string.
        origin: Origin header value. Defaults to the gateway URL's origin.

    Returns:
        A callable that returns a dict with keys: ``url``, ``headers``, ``transport``.

    Example::

        from authzen_backend.auth import ClientCredentialsAuth

        creds = ClientCredentialsAuth(
            token_url="https://idp.example.com/token",
            client_id="my-client",
            client_secret="my-secret",
        )
        import httpx
        client = httpx.Client()
        factory = mcp_session_params_factory(
            gateway_url="https://mcp.acme.com/v1/mcp",
            token_factory=lambda: creds.get_token(client),
        )
        params = factory()  # fresh token each time
    """
    if not gateway_url:
        raise ValueError("gateway_url must not be empty")
    if token_factory is None:
        raise ValueError("token_factory must not be None")

    def _make_params() -> dict[str, Any]:
        token = token_factory()
        return _build_params(gateway_url, token, protocol_version, origin)

    return _make_params


def _build_params(
    gateway_url: str,
    token: str,
    protocol_version: str,
    origin: str | None,
) -> dict[str, Any]:
    """Build the MCP session params dict."""
    resolved_origin = origin if origin is not None else _extract_origin(gateway_url)

    headers: dict[str, str] = {
        "Authorization": f"Bearer {token}",
        "Mcp-Protocol-Version": protocol_version,
    }
    if resolved_origin:
        headers["Origin"] = resolved_origin

    return {
        "url": gateway_url,
        "headers": headers,
        "transport": "streamable-http",
    }


def _extract_origin(url: str) -> str:
    """Extract scheme + authority from a URL for the Origin header."""
    if "://" not in url:
        return url
    scheme_rest = url.split("://", 1)
    scheme = scheme_rest[0]
    rest = scheme_rest[1]
    authority = rest.split("/", 1)[0]
    return f"{scheme}://{authority}"
