import attr
from django.test import TestCase
from rest_framework import status
from rest_framework.test import APIRequestFactory

from mantle_drf.viewsets import ModelViewSet, ReadOnlyModelViewSet
from tests.models import Item


@attr.define
class ItemShape:
    name: str
    slug: str


factory = APIRequestFactory()


class TestReadOnlyModelViewSet(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.item = Item.objects.create(name="VS", slug="vs")

    def test_list(self):
        class TestViewSet(ReadOnlyModelViewSet):
            queryset = Item.objects.all()
            shape_class = ItemShape

        view = TestViewSet.as_view({"get": "list"})
        request = factory.get("/")
        response = view(request)
        assert response.status_code == status.HTTP_200_OK
        assert len(response.data) == 1

    def test_retrieve(self):
        class TestViewSet(ReadOnlyModelViewSet):
            queryset = Item.objects.all()
            shape_class = ItemShape

        view = TestViewSet.as_view({"get": "retrieve"})
        request = factory.get("/")
        response = view(request, pk=self.item.pk)
        assert response.status_code == status.HTTP_200_OK
        assert response.data["name"] == "VS"


class TestModelViewSet(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.item = Item.objects.create(name="CRUD", slug="crud")

    def test_list(self):
        class TestViewSet(ModelViewSet):
            queryset = Item.objects.all()
            shape_class = ItemShape

        view = TestViewSet.as_view({"get": "list"})
        request = factory.get("/")
        response = view(request)
        assert response.status_code == status.HTTP_200_OK

    def test_create(self):
        class TestViewSet(ModelViewSet):
            queryset = Item.objects.all()
            shape_class = ItemShape

        view = TestViewSet.as_view({"post": "create"})
        request = factory.post("/", {"name": "New", "slug": "vs-new"}, format="json")
        response = view(request)
        assert response.status_code == status.HTTP_201_CREATED

    def test_retrieve(self):
        class TestViewSet(ModelViewSet):
            queryset = Item.objects.all()
            shape_class = ItemShape

        view = TestViewSet.as_view({"get": "retrieve"})
        request = factory.get("/")
        response = view(request, pk=self.item.pk)
        assert response.status_code == status.HTTP_200_OK

    def test_update(self):
        class TestViewSet(ModelViewSet):
            queryset = Item.objects.all()
            shape_class = ItemShape

        view = TestViewSet.as_view({"put": "update"})
        request = factory.put(
            "/", {"name": "Updated", "slug": "crud-updated"}, format="json"
        )
        response = view(request, pk=self.item.pk)
        assert response.status_code == status.HTTP_200_OK

    def test_destroy(self):
        class TestViewSet(ModelViewSet):
            queryset = Item.objects.all()
            shape_class = ItemShape

        view = TestViewSet.as_view({"delete": "destroy"})
        request = factory.delete("/")
        response = view(request, pk=self.item.pk)
        assert response.status_code == status.HTTP_204_NO_CONTENT
