"""Tests for PendingReviewBlocksWriteMixin / pending_review_blocks_write."""
from __future__ import annotations

import pytest
from django.contrib.auth import get_user_model
from django.http import HttpResponse
from django.test import RequestFactory
from django.views import View

from apps.core.permissions.pending_review import (
    PendingReviewBlocksWriteMixin,
    pending_review_blocks_write,
)

User = get_user_model()


class _Probe(PendingReviewBlocksWriteMixin, View):
    """A no-op CBV used to exercise the mixin."""

    def get(self, request, *a, **k):
        return HttpResponse("ok-get")

    def post(self, request, *a, **k):
        return HttpResponse("ok-post")


@pending_review_blocks_write
def _probe_fbv(request):
    return HttpResponse("ok-fbv")


@pytest.fixture
def pending(db):
    u = User.objects.create_user(
        email="pending@example.com",
        password="x",
        first_name="P",
        last_name="U",
    )
    u.pending_admin_review = True
    u.save(update_fields=["pending_admin_review"])
    return u


@pytest.fixture
def cleared(db):
    return User.objects.create_user(
        email="ok@example.com",
        password="x",
        first_name="O",
        last_name="K",
    )


def _attach_messages(request):
    """RequestFactory doesn't set up the messages framework; do it manually."""
    from django.contrib.messages.storage.fallback import FallbackStorage

    setattr(request, "session", {})
    setattr(request, "_messages", FallbackStorage(request))


def _request(method: str, user):
    rf = RequestFactory()
    req = rf.generic(method, "/")
    req.user = user
    _attach_messages(req)
    return req


def test_mixin_allows_get_for_pending_user(pending):
    resp = _Probe.as_view()(_request("GET", pending))
    assert resp.status_code == 200
    assert resp.content == b"ok-get"


def test_mixin_blocks_post_for_pending_user(pending):
    resp = _Probe.as_view()(_request("POST", pending))
    assert resp.status_code == 302  # redirect to dashboard


@pytest.mark.parametrize("method", ["PUT", "PATCH", "DELETE"])
def test_mixin_blocks_other_write_methods(pending, method):
    resp = _Probe.as_view()(_request(method, pending))
    assert resp.status_code == 302


def test_mixin_does_not_affect_cleared_user(cleared):
    resp = _Probe.as_view()(_request("POST", cleared))
    assert resp.status_code == 200


def test_decorator_blocks_post_for_pending_user(pending):
    resp = _probe_fbv(_request("POST", pending))
    assert resp.status_code == 302


def test_decorator_allows_get_for_pending_user(pending):
    resp = _probe_fbv(_request("GET", pending))
    assert resp.status_code == 200
