"""Exceptions for the unified user OAuth 2.1 authorization code flow.

All exceptions inherit from :class:`OAuthFlowError` so callers can catch the
entire hierarchy with a single ``except OAuthFlowError`` clause while still
differentiating specific failure modes when needed.

Exception → suggested HTTP status mapping for service layers:

    OAuthStateError              → 400 (invalid / expired state)
    OAuthRateLimitError          → 429 (too many callbacks)
    OAuthSecretResolutionError   → 500 (vault unavailable)
    OAuthProviderError           → 502 (upstream provider error)
    OAuthEnrichmentError         → 502 (only raised when required=True)
    CredentialStorageError       → 500 (storage failure — from vault.user_oauth)
"""


class OAuthFlowError(Exception):
    """Base exception for user OAuth authorization code flow errors."""


class OAuthStateError(OAuthFlowError):
    """Invalid or expired OAuth state token.

    Raised by :meth:`UnifiedOAuthFlow.handle_callback` when the ``state``
    parameter does not match any stored state (consumed, expired, or forged).
    """


class OAuthRateLimitError(OAuthFlowError):
    """Rate limit exceeded for OAuth callbacks.

    Raised when a single user ARN triggers more callbacks than
    ``rate_limit_max`` within ``rate_limit_window`` seconds.
    """


class OAuthProviderError(OAuthFlowError):
    """OAuth provider returned an error during token exchange.

    Raised when the token endpoint responds with a non-200 status or a
    network error occurs during the exchange HTTP POST.
    """


class OAuthEnrichmentError(OAuthFlowError):
    """A *required* metadata enrichment step failed after token exchange.

    Only raised when :attr:`EnrichmentStep.required` is ``True``. Non-required
    failures are logged as warnings and the flow continues.

    Attributes:
        url: The enrichment API endpoint that failed.
        reason: Human-readable description of the failure.
    """

    def __init__(self, url: str, reason: str) -> None:
        self.url = url
        self.reason = reason
        super().__init__(f"Enrichment failed for {url}: {reason}")


class OAuthSecretResolutionError(OAuthFlowError):
    """Vault provider could not resolve the client secret from the vault URI.

    Raised when :class:`~empowernow_common.vault.base.ReadableVaultProvider`
    raises an exception while fetching ``config.client_secret_ref`` during
    token exchange.
    """
