"""Django middleware for PyAuthz authorization.

PyAuthzMiddleware resolves the Subject from the request and attaches it
to request.pyauthz_subject. It also converts Denied exceptions to
structured 403 JSON responses.
"""

from __future__ import annotations

from collections.abc import Callable
from typing import Any

from pyauthz import PyAuthz, Subject
from pyauthz.core.errors import Denied

# Type for the subject resolver
SubjectResolver = Callable[[Any], Subject]

# Module-level storage for the PyAuthz instance and resolver.
# Set by PyAuthzMiddleware.__init__ and accessible via get_pyauthz()/get_subject().
_pyauthz_instance: PyAuthz | None = None
_subject_resolver: SubjectResolver | None = None


class PyAuthzMiddleware:
    """Django middleware that integrates PyAuthz authorization.

    Resolves the Subject before each request and catches Denied exceptions,
    returning structured 403 JSON responses.

    Configure in settings.py:
        MIDDLEWARE = ["pyauthz_django.PyAuthzMiddleware", ...]

    Set up in your Django app's ready() or urls.py:
        from pyauthz_django.middleware import configure_pyauthz
        configure_pyauthz(pyauthz=rp, subject_resolver=resolve_user)
    """

    def __init__(self, get_response: Callable) -> None:
        self.get_response = get_response

    def __call__(self, request: Any) -> Any:
        if _pyauthz_instance is None or _subject_resolver is None:
            return self.get_response(request)

        # Resolve subject and attach to request
        request.pyauthz = _pyauthz_instance
        request.pyauthz_subject = _subject_resolver(request)

        try:
            response = self.get_response(request)
        except Denied as exc:
            from django.http import JsonResponse

            decision = exc.decision
            return JsonResponse(
                {
                    "error": "forbidden",
                    "detail": decision.explain(),
                    "matched_policies": decision.matched_policies,
                    "reasoning": decision.reasoning,
                },
                status=403,
            )

        return response


def configure_pyauthz(
    *,
    pyauthz: PyAuthz,
    subject_resolver: SubjectResolver,
) -> None:
    """Configure the PyAuthz middleware with an engine and subject resolver.

    Call this during Django app initialization (e.g., in AppConfig.ready()
    or at module level in urls.py).

    Args:
        pyauthz: The PyAuthz engine instance.
        subject_resolver: Callable that extracts a Subject from a Django request.
    """
    global _pyauthz_instance, _subject_resolver
    _pyauthz_instance = pyauthz
    _subject_resolver = subject_resolver
