"""
Auth-guard evaluation — the adapter-agnostic core.

`enforce_auth` evaluates a function's `@client(auth=...)` requirement against an
`Identity` and raises `Unauthorized`/`Forbidden` on failure. A custom `auth=callable`
receives the adapter's NATIVE request (it may read request-specific state), passed
through opaquely — the core never introspects it.
"""

from __future__ import annotations

from typing import Any

from mizan_core.errors import Forbidden, InternalError, Unauthorized
from mizan_core.identity import Identity


def enforce_auth(
    identity: Identity | None,
    requirement: Any,
    native_request: Any = None,
) -> None:
    """Raise `Unauthorized`/`Forbidden` if `identity` fails `requirement`; else return.

    Requirement: None | True | "required" | "staff" | "superuser" | callable(native_request)->bool.
    """
    if requirement is None:
        return

    if callable(requirement):
        try:
            if not requirement(native_request):
                raise Forbidden("Access denied")
        except PermissionError as e:
            raise Forbidden(str(e) or "Access denied") from e
        return

    if not getattr(identity, "is_authenticated", False):
        raise Unauthorized("Authentication required")

    if requirement in (True, "required"):
        return
    if requirement == "staff":
        if not getattr(identity, "is_staff", False):
            raise Forbidden("Staff access required")
        return
    if requirement == "superuser":
        if not getattr(identity, "is_superuser", False):
            raise Forbidden("Superuser access required")
        return

    raise InternalError(f"Unknown auth requirement: {requirement!r}")
