from __future__ import annotations

from functools import wraps
from typing import Iterable, Callable, Optional

from django.contrib import messages
from django.contrib.auth.views import redirect_to_login
from django.shortcuts import redirect
from django.urls import reverse


def permissions_required(*perms: str, any_perm: bool = False, message: Optional[str] = None, login_view: str = "admin_frontend:login"):
    """Decorator to enforce one or more Django permissions on a view.

    - If the user is not authenticated, redirects to the admin login, preserving next.
    - If permissions fail, adds an error message and redirects back to the current URL.

    Usage:
        @permissions_required('recycle_core.assign_driver')
        def my_view(...):
            ...

        @permissions_required('app.perm_a', 'app.perm_b')  # ALL required
        def another(...):
            ...

        @permissions_required('app.perm_a', 'app.perm_b', any_perm=True)  # ANY required
        def another(...):
            ...
    """

    def decorator(view_func: Callable):
        @wraps(view_func)
        def _wrapped(request, *args, **kwargs):
            if not request.user.is_authenticated:
                return redirect_to_login(request.get_full_path(), login_url=reverse(login_view))

            # Normalize permissions list
            perms_list: Iterable[str] = perms or []

            allowed = False
            if any_perm:
                allowed = any(request.user.has_perm(p) for p in perms_list) if perms_list else True
            else:
                # ALL required
                allowed = request.user.has_perms(perms_list) if perms_list else True

            if not allowed:
                msg = message or (
                    "You do not have the required permission." if len(perms_list) <= 1
                    else "You do not have the required permissions."
                )
                try:
                    messages.error(request, msg)
                except Exception:
                    pass
                # Avoid redirect loops on POST-only endpoints by preferring HTTP_REFERER
                referer = request.META.get("HTTP_REFERER")
                if referer:
                    return redirect(referer)
                # Fallback to a safe dashboard
                try:
                    return redirect(reverse("admin_frontend:dashboard"))
                except Exception:
                    return redirect("/")

            return view_func(request, *args, **kwargs)

        return _wrapped

    return decorator
