from contextlib import contextmanager

from asgiref.local import Local

from wagtail.models import Site

_request_storage = Local()


@contextmanager
def with_request(request):
    """
    A context manager that stores the request in thread-local storage for the
    duration of the context. This allows code that doesn't have access to the
    request to retrieve it from get_current_request().

    It uses django's own local thread storage implementation, which is thread safe (in case we ever go django async mode).
    https://github.com/django/asgiref/blob/main/asgiref/local.py#L66

    Once the request finished (we rendered the response), the request and site are automatically removed from the storage again.
    """
    try:
        _request_storage.request = request
        _request_storage.site = Site.find_for_request(request)
        yield
    finally:
        try:
            del _request_storage.request
            del _request_storage.site
        except AttributeError:
            pass


def get_current_request():
    """Returns the current request if available."""
    return getattr(_request_storage, "request", None)


def get_current_site():
    """Returns the current site if available."""
    return getattr(_request_storage, "site", None)


class RequestContextMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        with with_request(request):
            return self.get_response(request)
