"""Interfaces every auth backend implements.

These two Protocols are the entire swap-out surface of the library:

- TokenProvider: how *this* agent gets a token to call another agent.
- TokenVerifier: how *this* agent checks a token someone else sent it.

Anything that satisfies these (structurally -- no subclassing required) can
be passed to RemoteAgentClient / PassportAuthMiddleware. Ship a mock for
tests, an OAuth2ClientCredentialsProvider + JWKSVerifier pair for Auth0,
Keycloak, Okta, or any standard OIDC IdP, or write your own for something
non-standard -- nothing else in the library needs to know or care.
"""
from __future__ import annotations

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


@dataclass(frozen=True)
class VerifiedClaims:
    """Normalized result of verifying an inbound token, regardless of IdP."""

    subject: str
    audience: str
    scopes: frozenset[str]
    raw: dict[str, Any] = field(default_factory=dict, compare=False)

    def has_scope(self, scope: str) -> bool:
        return scope in self.scopes


@runtime_checkable
class TokenProvider(Protocol):
    """Client-side: resolve a token scoped to a specific target audience."""

    async def get_token(self, audience: str) -> str: ...


@runtime_checkable
class TokenVerifier(Protocol):
    """Server-side: verify an inbound bearer token for an expected audience.

    Implementations raise a2a_passport.exceptions.TokenVerificationError on
    any failure (expired, bad signature, wrong audience, malformed) rather
    than returning a sentinel -- callers should not need to distinguish
    "verification said no" from "verification crashed".
    """

    async def verify(self, token: str, *, audience: str) -> VerifiedClaims: ...
