from django.contrib import messages
from django.middleware.csrf import get_token

from .http import location
from .settings import settings


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

    def __call__(self, request):
        response = self.get_response(request)

        # Inertia requests don't ever render templates, so they skip the typical Django
        # CSRF path. We'll manually add a CSRF token for every request here.
        get_token(request)

        if not self.is_inertia_request(request):
            return response

        if self.is_non_post_redirect(request, response):
            response.status_code = 303

        if self.is_stale(request):
            return self.force_refresh(request)

        return response

    def is_non_post_redirect(self, request, response):
        return self.is_redirect_request(response) and request.method in [
            "PUT",
            "PATCH",
            "DELETE",
        ]

    def is_inertia_request(self, request):
        return "X-Inertia" in request.headers

    def is_redirect_request(self, response):
        return response.status_code in [301, 302]

    def is_stale(self, request):
        return (
            request.headers.get("X-Inertia-Version", settings.INERTIA_VERSION)
            != settings.INERTIA_VERSION
        )

    def is_stale_inertia_get(self, request):
        return request.method == "GET" and self.is_stale(request)

    def force_refresh(self, request):
        messages.get_messages(request).used = False
        return location(request.build_absolute_uri())
