"""OAuth provider builder for HTTP transports using FastMCP 3 OAuthProxy."""

from __future__ import annotations

from typing import cast
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ims_mcp.config import RosettaConfig

from ims_mcp.constants import DEFAULT_OAUTH_SCOPES, TRANSPORT_HTTP


def build_oauth_provider(
    config: "RosettaConfig",
    client_storage: object | None = None,
) -> object | None:
    """Build a FastMCP ``OAuthProxy`` for HTTP transports.

    Returns ``None`` when the transport is not HTTP or when required OAuth
    environment variables are missing.  In that case the server runs without
    authentication (STDIO mode uses ``ROSETTA_API_KEY`` directly).

    Env vars:
      ROSETTA_OAUTH_SCOPE            — space-separated valid scopes advertised in
                                       .well-known/oauth-authorization-server
                                       (e.g. "openid email offline_access").
                                       Defaults to openid, email, offline_access.
      ROSETTA_OAUTH_EXTRA_SCOPES     — space-separated scopes forwarded to upstream
                                       IdP authorization endpoint via extra_authorize_params.
                                       Include "offline_access" to avoid daily re-auth
                                       tied to ssoSessionMaxLifespan. Optional.
      ROSETTA_JWT_SIGNING_KEY        — independent secret for signing FastMCP JWTs.
                                       Decouples JWT signing from ROSETTA_OAUTH_CLIENT_SECRET;
                                       client secret rotation does not invalidate sessions.
      ROSETTA_OAUTH_REVOCATION_ENDPOINT — upstream token revocation URL
                                       (e.g. Keycloak's /protocol/openid-connect/revoke).
                                       Enables token revocation propagation.
      FERNET_KEY                     — Fernet key for encrypting OAuth token storage in Redis.
    """
    if config.transport != TRANSPORT_HTTP:
        return None

    if not config.oauth_configured:
        return None

    from fastmcp.server.auth.oauth_proxy import OAuthProxy

    from ims_mcp.auth.introspection_cache import CachedIntrospectionTokenVerifier

    token_verifier = CachedIntrospectionTokenVerifier(
        introspection_url=config.oauth_introspection_endpoint,
        client_id=config.oauth_client_id,
        client_secret=config.oauth_client_secret,
    )

    base_url = config.resolve_oauth_base_url()

    # valid_scopes: advertised in .well-known/oauth-authorization-server (ROSETTA_OAUTH_SCOPE)
    valid_scopes: list[str] = (
        config.oauth_scope.split() if config.oauth_scope else DEFAULT_OAUTH_SCOPES
    )
    # extra_authorize_params: forwarded to upstream IdP authorization endpoint (ROSETTA_OAUTH_EXTRA_SCOPES)
    extra_authorize_params: dict[str, str] | None = (
        {"scope": config.oauth_extra_scopes} if config.oauth_extra_scopes else None
    )

    return cast(
        object,
        OAuthProxy(
            upstream_authorization_endpoint=config.oauth_authorization_endpoint,
            upstream_token_endpoint=config.oauth_token_endpoint,
            upstream_client_id=config.oauth_client_id,
            upstream_client_secret=config.oauth_client_secret,
            upstream_revocation_endpoint=config.oauth_revocation_endpoint or None,
            token_verifier=token_verifier,
            base_url=base_url,
            redirect_path=config.oauth_callback_path,
            require_authorization_consent=False,
            client_storage=client_storage,
            valid_scopes=valid_scopes,
            extra_authorize_params=extra_authorize_params,
            jwt_signing_key=config.oauth_jwt_signing_key,
        ),
    )
