"""Per-request memoisation of `is_allowed` results.

The IAM engine is called multiple times per request (DRF list endpoint
filters → object permission → audit hooks → serializer). For ABAC-heavy
policies the cost of `evaluate()` adds up, so we memoise on
``(actor_id, action, obj_pk_or_None)``.

Cache lifetime = one HTTP request. The middleware that creates the
RequestContext clears it on entry; explicit ``clear()`` is exposed for tests.
"""

from __future__ import annotations

import contextvars
from typing import Any

_cache: contextvars.ContextVar[dict[tuple[int | None, str, Any], bool] | None] = (
    contextvars.ContextVar("iam_cache", default=None)
)


def _store() -> dict[tuple[int | None, str, Any], bool]:
    s = _cache.get()
    if s is None:
        s = {}
        _cache.set(s)
    return s


def cache_key(actor_id: int | None, action: str, obj: Any | None) -> tuple[int | None, str, Any]:
    return (actor_id, action, getattr(obj, "pk", None) if obj is not None else None)


def get(key: tuple[int | None, str, Any]) -> bool | None:
    return _store().get(key)


def set(key: tuple[int | None, str, Any], value: bool) -> None:
    _store()[key] = value


def clear() -> None:
    _cache.set({})


__all__ = ["cache_key", "clear", "get", "set"]
