"""Pending-review enforcement primitive.

When a user signs up against a non-partner institution they land in a
``pending_admin_review=True`` state (see ``apps.core.authentication.forms``).
Until an administrator clears the flag, those users may **read** the platform
freely but must not perform write operations on RIMS / SME-Hub / REP authoring
views — otherwise they could submit grant applications, business records, or
course content while their identity is still being verified.

Two callables, same policy:

* ``PendingReviewBlocksWriteMixin`` — drop into any class-based view's MRO.
* ``pending_review_blocks_write`` — function-decorator equivalent.

Reads (GET / HEAD / OPTIONS) pass through unchanged so the user can preview
state while waiting; write methods (POST / PUT / PATCH / DELETE) bounce to
the dashboard with a flash message.
"""
from __future__ import annotations

from functools import wraps

from django.contrib import messages
from django.shortcuts import redirect
from django.urls import reverse

WRITE_METHODS: frozenset[str] = frozenset({"POST", "PUT", "PATCH", "DELETE"})

_PENDING_MESSAGE = (
    "Your account is awaiting administrator review. "
    "You can browse the platform but cannot submit changes yet."
)


def _is_pending(user) -> bool:
    return (
        getattr(user, "is_authenticated", False)
        and getattr(user, "pending_admin_review", False)
    )


def _redirect_with_flash(request):
    messages.warning(request, _PENDING_MESSAGE)
    try:
        target = reverse("core:dashboard")
    except Exception:  # noqa: BLE001
        target = "/"
    return redirect(target)


class PendingReviewBlocksWriteMixin:
    """Mixin: 302 to dashboard on write methods when the user is pending review.

    Apply alongside the view's existing role-gate mixin (RimsAccessMixin,
    EntrepreneurRequired, …). Place it FIRST in the MRO so the redirect runs
    before role checks — pending users see the friendly flash, not a 403.
    """

    def dispatch(self, request, *args, **kwargs):  # type: ignore[override]
        if request.method in WRITE_METHODS and _is_pending(request.user):
            return _redirect_with_flash(request)
        return super().dispatch(request, *args, **kwargs)


def pending_review_blocks_write(view_func):
    """FBV decorator equivalent of ``PendingReviewBlocksWriteMixin``."""

    @wraps(view_func)
    def _wrapper(request, *args, **kwargs):
        if request.method in WRITE_METHODS and _is_pending(request.user):
            return _redirect_with_flash(request)
        return view_func(request, *args, **kwargs)

    return _wrapper
