"""DRF + Django glue for the authorization engine."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from rest_framework.permissions import BasePermission

from simorgh.apps.iam.engine import is_allowed, is_allowed_object
from simorgh.core.context import current_request_context

if TYPE_CHECKING:
    from rest_framework.request import Request
    from rest_framework.views import APIView


class HasPermission(BasePermission):
    """DRF permission class.

    Views opt in by setting `required_permission = "module.resource.action"`,
    optionally overriding `get_required_permission(self, request, view)` for
    per-method codenames.
    """

    def has_permission(self, request: Request, view: APIView) -> bool:
        codename = getattr(view, "required_permission", None)
        getter = getattr(view, "get_required_permission", None)
        if callable(getter):
            codename = getter(request, view)
        if not codename:
            return True
        ctx = current_request_context()
        return is_allowed(ctx, codename)

    def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
        codename = getattr(view, "required_permission", None)
        getter = getattr(view, "get_required_permission", None)
        if callable(getter):
            codename = getter(request, view)
        if not codename:
            return True
        ctx = current_request_context()
        return is_allowed(ctx, codename, resource=obj)


class HasObjectPermission(BasePermission):
    """Object-level DRF permission class.

    Convenience wrapper that always invokes :func:`is_allowed_object` so the
    policy evaluator receives ``object_tenant_id``, ``object_org_node_id``,
    and ``object_owner_id`` derived from the target instance.

    Views opt in via ``required_object_permission = "module.resource.action"``.
    """

    def has_permission(self, request: Request, view: APIView) -> bool:
        codename = getattr(view, "required_object_permission", None) or getattr(
            view, "required_permission", None
        )
        if not codename:
            return True
        ctx = current_request_context()
        if not ctx.is_authenticated:
            return False
        return codename in ctx.permissions or ctx.is_superuser

    def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
        codename = getattr(view, "required_object_permission", None) or getattr(
            view, "required_permission", None
        )
        if not codename:
            return True
        ctx = current_request_context()
        return is_allowed_object(ctx, codename, obj)


def require_permission(codename: str):
    """View decorator for FBVs (rare — we prefer DRF classes)."""

    from functools import wraps

    from django.http import HttpResponseForbidden

    def wrap(view_fn):
        @wraps(view_fn)
        def inner(request, *args, **kwargs):
            if not is_allowed(current_request_context(), codename):
                return HttpResponseForbidden()
            return view_fn(request, *args, **kwargs)

        return inner

    return wrap
