from django_grainy_test.models import ModelA
from grainy.const import PERM_CREATE, PERM_DELETE, PERM_READ, PERM_UPDATE
from grainy.core import PermissionSet
from rest_framework.test import APIClient

from .util import UserTestCase


class TestGrainyViewSet(UserTestCase):
    @classmethod
    def setUpTestData(cls):
        UserTestCase.setUpTestData()

        cls.users["user_a"].grainy_permissions.add_permission_set(
            PermissionSet(
                {
                    "api": PERM_READ | PERM_CREATE | PERM_UPDATE | PERM_DELETE,
                    "api.a.*.nested_dict.secret": PERM_READ,
                }
            )
        )

        cls.users["user_b"].grainy_permissions.add_permission_set(
            PermissionSet({"api": PERM_READ, "api.a_x": PERM_READ})
        )

        ModelA.objects.create(name="Test1")

    def test_grainy_viewset_gate(self):
        client_a = APIClient()
        client_a.force_authenticate(user=self.users["user_a"])

        r = client_a.post("/a/", {"name": "bla"})
        self.assertEqual(r.status_code, 201)
        r = client_a.put("/a/2/", {"name": "bla2"})
        self.assertEqual(r.status_code, 200)
        r = client_a.patch("/a/2/", {"name": "bla3"})
        self.assertEqual(r.status_code, 200)
        r = client_a.delete("/a/2/", follow=True)
        self.assertEqual(r.status_code, 404)

        r = client_a.get("/a_x/1/")
        self.assertEqual(r.status_code, 403)
        r = client_a.delete("/a_x/1/")
        self.assertEqual(r.status_code, 403)

        client_b = APIClient()
        client_b.force_authenticate(user=self.users["user_b"])

        r = client_b.post("/a/", {"name": "bla"})
        self.assertEqual(r.status_code, 403)
        r = client_b.put("/a/1/", {"name": "bla2"})
        self.assertEqual(r.status_code, 403)
        r = client_b.patch("/a/1/", {"name": "bla3"})
        self.assertEqual(r.status_code, 403)
        r = client_b.delete("/a/1/", follow=True)
        self.assertEqual(r.status_code, 403)

        r = client_b.get("/a_x/1/")
        self.assertEqual(r.status_code, 200)
        r = client_b.delete("/a_x/1/")
        self.assertEqual(r.status_code, 403)

    def test_grainy_viewset_list(self):
        client = APIClient()
        client.force_authenticate(user=self.users["user_a"])
        response = client.get("/a/?format=json", follow=True)

        self.assertEqual(
            response.data,
            [
                {
                    "name": "Test1",
                    "id": 1,
                    "nested_dict": {
                        "secret": {"hidden": "data"},
                        "something": "public",
                    },
                }
            ],
        )

        client = APIClient()
        client.force_authenticate(user=self.users["user_b"])
        response = client.get("/a/?format=json", follow=True)

        self.assertEqual(
            response.data,
            [{"name": "Test1", "id": 1, "nested_dict": {"something": "public"}}],
        )

    def test_grainy_viewset_retrieve(self):
        client = APIClient()
        client.force_authenticate(user=self.users["user_a"])
        response = client.get("/a/1/?format=json", follow=True)

        self.assertEqual(
            response.data,
            {
                "name": "Test1",
                "id": 1,
                "nested_dict": {"secret": {"hidden": "data"}, "something": "public"},
            },
        )

        client = APIClient()
        client.force_authenticate(user=self.users["user_b"])
        response = client.get("/a/1/?format=json", follow=True)

        self.assertEqual(
            response.data,
            {"name": "Test1", "id": 1, "nested_dict": {"something": "public"}},
        )
