"""``AuthFlow`` — Protocol for resolving credentials before a probe is sent.

See: ``DESIGN.md`` §3.6 (AuthFlow as primitive). Concrete implementations
(``BearerAuth``, ``BasicAuth``, ``ApiKeyAuth``, ``CookieAuth``,
``CustomAuth``) land in Phase 1.5 of this implementation. v0.1 ships
the Protocol so :class:`mgf.apiprobe.core.probe.Probe` can hold an
auth field with a stable type.

The Protocol is **synchronous** for v0.1. Auth flows we ship initially
(bearer / basic / api-key / cookie / custom) all resolve credentials
without I/O — they read env vars, vault entries, or in-memory state.
OAuth2 flows that need a token endpoint round-trip land in v0.6;
that release will add :class:`AsyncAuthFlow` as a sibling protocol
(or migrate this one — decision deferred). Concrete classes built
against this Protocol will keep working either way.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Protocol, runtime_checkable


@dataclass(frozen=True, slots=True)
class AuthCredentials:
    """Materialised auth fragments to attach to a single request.

    Different auth schemes target different fragments — bearer adds a
    header; api-key may use a header OR a query param; cookie auth
    sets cookies. Carrying all three in one shape lets the transport
    layer assemble the request without case-analysis.

    Frozen for the same reason :class:`mgf.apiprobe.core.probe.Probe`
    is frozen — auth credentials shouldn't mutate after they're
    resolved.
    """

    headers: tuple[tuple[str, str], ...] = ()
    cookies: tuple[tuple[str, str], ...] = ()
    query_params: tuple[tuple[str, str], ...] = ()
    extras: tuple[tuple[str, str], ...] = field(default_factory=tuple)
    """Reserved for transport-specific signals (e.g., httpx auth helpers).

    Not consumed in v0.1; reserved for forward compatibility with the
    transport layer (Phase 1.6 of this implementation).
    """


@runtime_checkable
class AuthFlow(Protocol):
    """Protocol for resolving and applying authentication.

    Concrete implementations (Phase 1.5):

    - ``BearerAuth``  — ``Authorization: Bearer <token>`` from env / vault
    - ``BasicAuth``   — ``Authorization: Basic <b64(user:pass)>``
    - ``ApiKeyAuth``  — header or query param
    - ``CookieAuth``  — sets a cookie
    - ``CustomAuth``  — caller-supplied callable

    Implementations are :class:`runtime_checkable`-compatible so the
    transport layer can ``isinstance(x, AuthFlow)`` for diagnostics
    without hard-coding the concrete classes.
    """

    name: str
    """Short identifier used in :class:`mgf.apiprobe.exceptions.AuthError`
    messages and in reports (e.g., ``"bearer"``, ``"vault:stripe-key"``)."""

    def prepare(self) -> AuthCredentials:
        """Resolve credentials.

        Raises :class:`mgf.apiprobe.exceptions.AuthError` if the
        credentials cannot be resolved (env var unset, vault key
        missing). MUST NOT raise for "401 Unauthorized at the
        provider" — that is the provider's response and surfaces as
        a :class:`~mgf.apiprobe.core.finding.Finding` with
        ``RootCause.AUTH``.
        """


__all__ = [
    "AuthCredentials",
    "AuthFlow",
]
