from django.contrib.auth import get_user_model
from django.test import Client, TestCase
from django.urls import reverse_lazy, reverse

from gestion.models import ErnestoUser
from propositions.models import Answer, Proposition

User = get_user_model()


def new_user(username):
    u = User.objects.create_user(username=username)
    ErnestoUser.objects.create(user=u, slug=username, is_ernesto=True)
    return u


class PropositionCreateTest(TestCase):
    url = reverse_lazy("propositions:create")

    def test_anonymous_cannot_get(self):
        response = Client().get(self.url)
        self.assertRedirects(response, "/login?next={}".format(self.url))

    def test_ernesto_user_can_get(self):
        user = new_user("toto")
        client = Client()
        client.force_login(user)

        response = client.get(self.url)
        self.assertEqual(response.status_code, 200)

    def test_ernesto_user_can_post(self):
        user = new_user("toto")
        client = Client()
        client.force_login(user)

        data = {"name": "foo", "artist": "bar", "link": "example.com"}
        client.post(self.url, data)
        proposition = Proposition.objects.all()
        self.assertEqual(1, proposition.count())

        proposition = proposition.get()
        self.assertEqual(proposition.name, "foo")
        self.assertEqual(proposition.artist, "bar")
        self.assertEqual(proposition.link, "http://example.com")
        self.assertEqual(proposition.user, user)


class PropositionDeleteTest(TestCase):
    def setUp(self):
        self.owner = new_user("owner")
        self.random_user = new_user("toto")
        self.chef = new_user("chef")
        self.chef.profile.is_chef = True
        self.chef.profile.save()

        proposition = Proposition.objects.create(name="prop", user=self.owner)
        self.url = reverse("propositions:delete", args=(proposition.id,))

    def test_anonymous_cannot_get(self):
        response = Client().get(self.url)
        self.assertRedirects(response, "/login?next={}".format(self.url))

    def test_anonymous_cannot_post(self):
        response = Client().post(self.url, {})
        self.assertRedirects(response, "/login?next={}".format(self.url))
        self.assertTrue(Proposition.objects.exists())

    def test_random_user_cannot_get(self):
        client = Client()
        client.force_login(self.random_user)
        response = client.get(self.url)
        self.assertEqual(response.status_code, 403)

    def test_not_owner_cannot_post(self):
        client = Client()
        client.force_login(self.random_user)
        response = client.post(self.url, {})
        self.assertEqual(response.status_code, 403)
        self.assertTrue(Proposition.objects.exists())

    def test_chef_can_get(self):
        client = Client()
        client.force_login(self.chef)
        response = client.get(self.url)
        self.assertEqual(response.status_code, 200)

    def test_chef_can_post(self):
        client = Client()
        client.force_login(self.chef)
        client.post(self.url, {})
        self.assertFalse(Proposition.objects.exists())

    def test_owner_can_get(self):
        client = Client()
        client.force_login(self.owner)
        response = client.get(self.url)
        self.assertEqual(response.status_code, 200)

    def test_owner_can_post(self):
        client = Client()
        client.force_login(self.owner)
        client.post(self.url, {})
        self.assertFalse(Proposition.objects.exists())


class PropositionListTest(TestCase):
    url = reverse_lazy("propositions:list")

    def setUp(self):
        self.user = new_user("toto")
        for name in ["foo", "bar", "baz"]:
            p = Proposition.objects.create(name=name, user=self.user)
            Answer.objects.create(proposition=p, user=self.user, answer=Answer.YES)
        for name in ["oof", "rab", "zab"]:
            p = Proposition.objects.create(name=name, user=self.user)
            Answer.objects.create(proposition=p, user=self.user, answer=Answer.NO)

    def test_anonymous_cannot_get(self):
        response = Client().get(self.url)
        self.assertRedirects(response, "/login?next={}".format(self.url))

    def test_ernesto_user_can_get(self):
        client = Client()
        client.force_login(self.user)

        response = client.get(self.url)
        self.assertEqual(response.status_code, 200)


class ReponseTest(TestCase):
    def setUp(self):
        self.user = new_user("toto")
        self.prop = Proposition.objects.create(name="foo", user=self.user)

    def _url(self, rep):
        assert rep in Answer.REP_CHOICES
        return reverse("propositions:{}".format(rep), args=(self.prop.id,))

    def test_anonymous_cannot_get(self):
        client = Client()

        url = reverse("propositions:oui", args=(self.prop.id,))
        response = client.get(url)
        self.assertRedirects(response, "/login?next={}".format(url))

        url = reverse("propositions:non", args=(self.prop.id,))
        response = client.get(url)
        self.assertRedirects(response, "/login?next={}".format(url))

    def test_ernesto_user_can_get(self):
        client = Client()
        client.force_login(self.user)

        client.get(reverse("propositions:oui", args=(self.prop.id,)))
        self.prop.refresh_from_db()
        self.assertEqual(
            list(self.prop.answer_set.values_list("answer", flat=True)), [Answer.YES],
        )

        client.get(reverse("propositions:non", args=(self.prop.id,)))
        self.prop.refresh_from_db()
        self.assertEqual(
            list(self.prop.answer_set.values_list("answer", flat=True)), [Answer.NO]
        )
