import json
from unittest import mock

from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse

from gestioncof.tests.mixins import ViewTestCaseMixin

from .utils import (
    create_petitcours_ability,
    create_petitcours_demande,
    create_petitcours_subject,
)

User = get_user_model()


class PetitCoursDemandeListViewTestCase(ViewTestCaseMixin, TestCase):
    url_name = "petits-cours-demandes-list"
    url_expected = "/gestion/petitcours/demandes"

    auth_user = "staff"
    auth_forbidden = [None, "user", "member"]

    def setUp(self):
        super().setUp()
        self.demande1 = create_petitcours_demande()
        self.demande2 = create_petitcours_demande()
        self.demande3 = create_petitcours_demande()

    def test_get(self):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(len(resp.context["object_list"]), 3)


class PetitCoursDemandeDetailListViewTestCase(ViewTestCaseMixin, TestCase):
    url_name = "petits-cours-demande-details"

    auth_user = "staff"
    auth_forbidden = [None, "user", "member"]

    @property
    def url_kwargs(self):
        return {"pk": self.demande.pk}

    @property
    def url_expected(self):
        return "/gestion/petitcours/demandes/{}".format(self.demande.pk)

    def setUp(self):
        super().setUp()
        self.demande = create_petitcours_demande()

    def test_get(self):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 200)


class PetitCoursInscriptionViewTestCase(ViewTestCaseMixin, TestCase):
    url_name = "petits-cours-inscription"
    url_expected = "/gestion/petitcours/inscription"

    http_methods = ["GET", "POST"]

    auth_user = "member"
    # Also forbidden for "user". Test below.
    auth_forbidden = [None]

    def setUp(self):
        super().setUp()
        self.user = self.users["member"]
        self.cofprofile = self.user.profile

        self.subject1 = create_petitcours_subject(name="Matière 1")
        self.subject2 = create_petitcours_subject(name="Matière 2")

    def test_get_forbidden_user_not_cof(self):
        self.client.force_login(
            self.users["user"], backend="django.contrib.auth.backends.ModelBackend"
        )
        resp = self.client.get(self.url)
        self.assertRedirects(resp, reverse("cof-denied"))

    def test_get(self):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 200)

    @property
    def base_post_data(self):
        return {
            "petitcoursability_set-TOTAL_FORMS": "3",
            "petitcoursability_set-INITIAL_FORMS": "0",
            "petitcoursability_set-MIN_NUM_FORMS": "0",
            "petitcoursability_set-MAX_NUM_FORMS": "1000",
            "remarques": "",
        }

    def test_post(self):
        data = dict(
            self.base_post_data,
            **{
                "petitcoursability_set-TOTAL_FORMS": "2",
                "petitcoursability_set-0-id": "",
                "petitcoursability_set-0-user": "",
                "petitcoursability_set-0-matiere": str(self.subject1.pk),
                "petitcoursability_set-0-niveau": "college",
                "petitcoursability_set-0-agrege": "1",
                # "petitcoursability_set-0-DELETE": "1",
                "petitcoursability_set-1-id": "",
                "petitcoursability_set-1-user": "",
                "petitcoursability_set-1-matiere": str(self.subject2.pk),
                "petitcoursability_set-1-niveau": "lycee",
                # "petitcoursability_set-1-agrege": "1",
                # "petitcoursability_set-1-DELETE": "1",
                # "receive_proposals": "1",
                "remarques": "Une remarque",
            },
        )
        resp = self.client.post(self.url, data)

        self.assertEqual(resp.status_code, 200)
        self.cofprofile.refresh_from_db()
        self.assertEqual(self.cofprofile.petits_cours_accept, False)
        self.assertEqual(self.cofprofile.petits_cours_remarques, "Une remarque")
        self.assertEqual(self.user.petitcoursability_set.count(), 2)
        ability1 = self.user.petitcoursability_set.get(matiere=self.subject1)
        self.assertEqual(ability1.niveau, "college")
        self.assertTrue(ability1.agrege)
        ability2 = self.user.petitcoursability_set.get(matiere=self.subject2)
        self.assertEqual(ability2.niveau, "lycee")
        self.assertFalse(ability2.agrege)

    def test_post_delete(self):
        ability1 = create_petitcours_ability(user=self.user)
        ability2 = create_petitcours_ability(user=self.user)

        data = dict(
            self.base_post_data,
            **{
                "petitcoursability_set-INITIAL_FORMS": "2",
                "petitcoursability_set-TOTAL_FORMS": "2",
                "petitcoursability_set-0-id": str(ability1.pk),
                "petitcoursability_set-0-user": "",
                "petitcoursability_set-0-matiere": str(self.subject1.pk),
                "petitcoursability_set-0-niveau": "college",
                "petitcoursability_set-0-agrege": "1",
                "petitcoursability_set-0-DELETE": "1",
                "petitcoursability_set-1-id": str(ability2.pk),
                "petitcoursability_set-1-user": str(self.user.pk),
                "petitcoursability_set-1-matiere": str(self.subject2.pk),
                "petitcoursability_set-1-niveau": "lycee",
                # "petitcoursability_set-1-agrege": "1",
                "petitcoursability_set-1-DELETE": "1",
            },
        )
        resp = self.client.post(self.url, data)

        self.assertEqual(resp.status_code, 200)
        self.assertFalse(self.user.petitcoursability_set.all())


class PetitCoursTraitementViewTestCase(ViewTestCaseMixin, TestCase):
    url_name = "petits-cours-demande-traitement"

    http_methods = ["GET", "POST"]

    auth_user = "staff"
    auth_forbidden = [None, "user", "member"]

    @property
    def url_kwargs(self):
        return {"demande_id": self.demande.pk}

    @property
    def url_expected(self):
        return "/gestion/petitcours/demandes/{}/traitement".format(self.demande.pk)

    def setUp(self):
        super().setUp()
        self.user = self.users["member"]
        self.user.profile.petits_cours_accept = True
        self.user.profile.save()
        self.subject = create_petitcours_subject()
        self.demande = create_petitcours_demande(niveau="college")
        self.demande.matieres.add(self.subject)

    def test_get(self):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 200)

    def test_get_with_match(self):
        create_petitcours_ability(
            user=self.user, matiere=self.subject, niveau="college"
        )

        resp = self.client.get(self.url)

        self.assertEqual(resp.status_code, 200)
        self.assertListEqual(
            list(resp.context["proposals"]), [(self.subject, [self.user])]
        )
        self.assertEqual(
            resp.context["attribdata"], json.dumps([(self.subject.id, [self.user.id])])
        )

    def test_post_with_match(self):
        create_petitcours_ability(
            user=self.user, matiere=self.subject, niveau="college"
        )

        data = {
            "attribdata": json.dumps([(self.subject.pk, [self.user.pk])]),
            "extra": "",
        }
        resp = self.client.post(self.url, data)

        self.assertEqual(resp.status_code, 200)
        self.demande.refresh_from_db()
        self.assertTrue(self.demande.traitee)
        self.assertEqual(self.demande.traitee_par, self.users["staff"])
        self.assertIsNotNone(self.demande.processed)


class PetitCoursRetraitementViewTestCase(ViewTestCaseMixin, TestCase):
    url_name = "petits-cours-demande-retraitement"

    http_methods = ["GET", "POST"]

    auth_user = "staff"
    auth_forbidden = [None, "user", "member"]

    @property
    def url_kwargs(self):
        return {"demande_id": self.demande.pk}

    @property
    def url_expected(self):
        return "/gestion/petitcours/demandes/{}/retraitement".format(self.demande.pk)

    def setUp(self):
        super().setUp()
        self.demande = create_petitcours_demande()

    def test_get(self):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 200)


class PetitCoursDemandeViewTestCase(ViewTestCaseMixin, TestCase):
    url_name = "petits-cours-demande"
    url_expected = "/gestion/petitcours/demande"

    http_methods = ["GET", "POST"]

    auth_user = None
    auth_forbidden = []

    def setUp(self):
        super().setUp()
        self.subject1 = create_petitcours_subject()
        self.subject2 = create_petitcours_subject()

    def test_get(self):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 200)

    @mock.patch("hcaptcha.fields.hCaptchaField.clean")
    def test_post(self, mock_clean):
        data = {
            "name": "Le nom",
            "email": "lemail@mail.net",
            "phone": "0123456789",
            "quand": "matin, midi et soir",
            "freq": "tous les jours",
            "lieu": "partout",
            "matieres": [str(self.subject1.pk), str(self.subject2.pk)],
            "agrege_requis": "1",
            "niveau": "lycee",
            "remarques": "no comment",
            "h-captcha-response": 1,
        }
        resp = self.client.post(self.url, data)

        self.assertEqual(resp.status_code, 200)
        self.assertTrue(resp.context["success"], msg=str(resp.context["form"].errors))


class PetitCoursDemandeRawViewTestCase(ViewTestCaseMixin, TestCase):
    url_name = "petits-cours-demande-raw"
    url_expected = "/gestion/petitcours/demande-raw"

    http_methods = ["GET", "POST"]

    auth_user = None
    auth_forbidden = []

    def setUp(self):
        super().setUp()
        self.subject1 = create_petitcours_subject()
        self.subject2 = create_petitcours_subject()

    def test_get(self):
        resp = self.client.get(self.url)
        self.assertEqual(resp.status_code, 200)

    @mock.patch("hcaptcha.fields.hCaptchaField.clean")
    def test_post(self, mock_clean):
        data = {
            "name": "Le nom",
            "email": "lemail@mail.net",
            "phone": "0123456789",
            "quand": "matin, midi et soir",
            "freq": "tous les jours",
            "lieu": "partout",
            "matieres": [str(self.subject1.pk), str(self.subject2.pk)],
            "agrege_requis": "1",
            "niveau": "lycee",
            "remarques": "no comment",
            "h-captcha-response": 1,
        }
        resp = self.client.post(self.url, data)

        self.assertEqual(resp.status_code, 200)
        self.assertTrue(resp.context["success"], msg=str(resp.context["form"].errors))
