from allauth.socialaccount.models import SocialAccount
from allauth_cas.test.testcases import CASTestCase
from allauth_ens.adapter import deprecate_clippers

from datetime import date

from django.test import TestCase
from django.urls import reverse
from django.conf import settings

from .models import User, Normalien, Lieu, Stage, StageMatiere, AvisLieu

class ExperiENSTestCase(CASTestCase):
    
    # Dummy database
    
    def setUp(self):
        self.u_conscrit = User.objects.create_user('conscrit',
                                                   'conscrit@ens.fr',
                                                   'conscrit')
        self.p_conscrit = self.u_conscrit.profil
        self.p_conscrit.nom="Petit conscrit"
        self.p_conscrit.promotion="Serpentard 2000"
        self.p_conscrit.bio="Je suis un petit conscrit"
        self.p_conscrit.save()

        self.sa_conscrit = SocialAccount(user=self.u_conscrit,
                                         provider="clipper",
                                         uid="conscrit")
        self.sa_conscrit.save()
        
        self.u_archi = User.objects.create_user('archicube',
                                                'archicube@ens.fr',
                                                'archicube')
        self.p_archi = self.u_archi.profil
        self.p_archi.nom="Vieil archicube"
        self.p_archi.promotion="Gryffondor 1994"
        self.p_archi.bio="Je suis un vieil archicube"

        self.lieu1 = Lieu(nom="Beaux-Bâtons", type_lieu="universite",
                          ville="Brocéliande", pays="FR",
                          coord="POINT(-1.63971 48.116382)")
        self.lieu1.save()
        self.lieu2 = Lieu(nom="Durmstrang", type_lieu="universite",
                          ville="Edimbourg", pays="GB",
                          coord="POINT(56.32153 -1.259715)")
        self.lieu2.save()

        self.matiere1 = StageMatiere(nom="Arithmancie", slug="arithmancie")
        self.matiere1.save()
        self.matiere2 = StageMatiere(nom="Sortilège", slug="sortilege")
        self.matiere2.save()
        
        self.cstage1 = Stage(auteur=self.p_conscrit, sujet="Wingardium Leviosa",
                             date_debut=date(2000, 5, 10),
                             date_fin=date(2000, 8, 26),
                             type_stage="recherche",
                             niveau_scol="M1", public=True)
        self.cstage1.save()
        self.cstage1.matieres.add(self.matiere1)
        alieu1 = AvisLieu(stage=self.cstage1, lieu=self.lieu1,
                          chapo="Trop bien")
        alieu1.save()

        self.cstage2 = Stage(auteur=self.p_conscrit, sujet="Avada Kedavra",
                             date_debut=date(2001, 5, 10),
                             date_fin=date(2001, 8, 26),
                             type_stage="sejour_dri",
                             niveau_scol="M2", public=False)
        self.cstage2.save()
        self.cstage2.matieres.add(self.matiere2)
        alieu2 = AvisLieu(stage=self.cstage2, lieu=self.lieu2,
                          chapo="Trop nul")
        alieu2.save()

        
        self.astage1 = Stage(auteur=self.p_archi, sujet="Alohomora",
                             date_debut=date(1994, 5, 10),
                             date_fin=date(1994, 8, 26),
                             type_stage="recherche",
                             niveau_scol="M2", public=True)
        self.astage1.save()
        self.astage1.matieres.add(self.matiere2)
        alieu3 = AvisLieu(stage=self.astage1, lieu=self.lieu1,
                          chapo="Trop moyen")
        alieu3.save()

    def assertRedirectToLogin(self, testurl):
        r = self.client.get(testurl)
        return self.assertRedirects(r, settings.LOGIN_URL+"?next="+testurl)

    def assertPageNotFound(self, testurl):
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 404)







"""
ACCÈS PUBLICS
"""
class PublicViewsTest(ExperiENSTestCase):
    """
    Vérifie que les fiches de stages ne sont pas visibles hors connexion
    """
    def test_stage_visibility_public(self):
        self.assertRedirectToLogin(reverse('avisstage:stage',
                                           kwargs={'pk':self.cstage1.id}))
        
        self.assertRedirectToLogin(reverse('avisstage:stage',
                                           kwargs={'pk':self.cstage2.id}))
        
        self.assertRedirectToLogin(reverse('avisstage:stage',
                                           kwargs={'pk':self.astage1.id}))


    """
    Vérifie que les profils de normaliens ne sont pas visibles hors connexion
    """
    def test_profil_visibility_public(self):
        self.assertRedirectToLogin(reverse(
            'avisstage:profil', kwargs={'username': self.u_conscrit.username}))

        self.assertRedirectToLogin(reverse(
            'avisstage:profil', kwargs={'username': self.u_archi.username}))

                                   
    """
    Vérifie que la recherche n'est pas accessible hors connexion
    """
    def test_pages_visibility_public(self):
        self.assertRedirectToLogin(reverse('avisstage:recherche'))

        self.assertRedirectToLogin(reverse('avisstage:recherche_resultats'))

        self.assertRedirectToLogin(reverse('avisstage:stage_items'))

        self.assertRedirectToLogin(reverse('avisstage:feedback'))

        self.assertRedirectToLogin(reverse('avisstage:moderation'))

    """
    Vérifie que l'API n'est pas accessible hors connexion
    """
    def test_api_visibility_public(self):
        testurl = reverse('avisstage:api_dispatch_list',
                          kwargs={"resource_name": "lieu",
                                  "api_name": "v1"})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 401)
        
        testurl = reverse('avisstage:api_dispatch_list',
                          kwargs={"resource_name": "stage",
                                  "api_name": "v1"})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 401)
        
        testurl = reverse('avisstage:api_dispatch_list',
                          kwargs={"resource_name": "profil",
                                  "api_name": "v1"})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 401)

    
    """
    Vérifie que les pages d'édition ne sont pas accessible hors connexion
    """
    def test_edit_visibility_public(self):
        self.assertRedirectToLogin(reverse(
            'avisstage:stage_edit', kwargs={'pk':self.cstage1.id}))
        
        self.assertRedirectToLogin(reverse(
            'avisstage:stage_edit', kwargs={'pk':self.astage1.id}))

        self.assertRedirectToLogin(reverse(
            'avisstage:stage_publication', kwargs={'pk':self.cstage1.id}))

        self.assertRedirectToLogin(reverse(
            'avisstage:stage_publication', kwargs={'pk':self.astage1.id}))

        self.assertRedirectToLogin(reverse('avisstage:stage_ajout'))

        self.assertRedirectToLogin(reverse('avisstage:profil_edit'))






"""
ACCÈS ARCHICUBE
"""
class ArchicubeViewsTest(ExperiENSTestCase):
    def setUp(self):
        super().setUp()
        self.client.login(username='archicube', password='archicube')

    def assert403Archicubes(self, testurl):
        r = self.client.get(testurl)
        return self.assertRedirects(r, reverse('avisstage:403-archicubes'))

    """
    Vérifie que les seules fiches de stages visibles sont les siennes
    """
    def test_stage_visibility_archi(self):
        self.assertPageNotFound(reverse('avisstage:stage',
                                        kwargs={'pk':self.cstage1.id}))
        
        self.assertPageNotFound(reverse('avisstage:stage',
                                        kwargs={'pk':self.cstage2.id}))
        
        testurl = reverse('avisstage:stage',
                          kwargs={'pk':self.astage1.id})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)


    """
    Vérifie que le seul profil visible est le sien
    """
    def test_profil_visibility_archi(self):
        self.assertPageNotFound(reverse(
            'avisstage:profil', kwargs={'username': self.u_conscrit.username}))

        testurl = reverse('avisstage:profil',
                          kwargs={'username': self.u_archi.username})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

                                   
    """
    Vérifie que la recherche n'est pas accessible
    """
    def test_pages_visibility_archi(self):
        self.assert403Archicubes(reverse('avisstage:recherche'))
        
        self.assert403Archicubes(reverse('avisstage:recherche_resultats'))

        self.assert403Archicubes(reverse('avisstage:stage_items'))

        testurl = reverse('avisstage:feedback')
        r = self.client.post(testurl, {"objet": "Contact",
                                       "message": "Ceci est un texte"})
        self.assertRedirects(r, reverse('avisstage:index'))

        testurl = reverse('avisstage:moderation')
        r = self.client.get(testurl)
        self.assertRedirects(r, reverse('admin:login')+"?next="+testurl)


    """
    Vérifie que la seule API accessible est celle des lieux
    """
    def test_api_visibility_archi(self):
        testurl = reverse('avisstage:api_dispatch_list',
                          kwargs={"resource_name": "lieu",
                                  "api_name": "v1"})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)
        
        testurl = reverse('avisstage:api_dispatch_list',
                          kwargs={"resource_name": "stage",
                                  "api_name": "v1"})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 401)
        
        testurl = reverse('avisstage:api_dispatch_list',
                          kwargs={"resource_name": "profil",
                                  "api_name": "v1"})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 401)

    
    """
    Vérifie que le seul stage modifiable est le sien
    """
    def test_edit_visibility_archi(self):
        testurl = reverse('avisstage:stage_edit', kwargs={'pk':self.cstage1.id})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 403)

        testurl = reverse('avisstage:stage_edit', kwargs={'pk':self.astage1.id})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

        testurl = reverse('avisstage:stage_publication',
                          kwargs={'pk':self.cstage1.id})
        r = self.client.post(testurl, {"publier": True})
        self.assertEqual(r.status_code, 403)

        testurl = reverse('avisstage:stage_publication',
                          kwargs={'pk':self.astage1.id})
        r = self.client.post(testurl, {"publier": True})
        self.assertRedirects(r, reverse('avisstage:stage',
                                        kwargs={"pk": self.astage1.id}))
        
        testurl = reverse('avisstage:stage_ajout')
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)
        
        testurl = reverse('avisstage:profil_edit')
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

        # TODO : test post()


class DeprecatedArchicubeViewsTest(ArchicubeViewsTest):
    def setUp(self):
        super().setUp()
        
        self.sa_archi = SocialAccount(user=self.u_archi,
                                      provider="clipper",
                                      uid="archicube")
        self.sa_archi.save()

        deprecate_clippers()
        
        self.client.login(username='archicube', password='archicube')




"""
ACCÈS EN SCOLARITE
"""
class ScolariteViewsTest(ExperiENSTestCase):
    def setUp(self):
        super().setUp()
        
        self.u_vieuxcon = User.objects.create_user('vieuxcon',
                                                   'vieuxcon@ens.fr',
                                                   'vieuxcon')
        self.p_vieuxcon = self.u_vieuxcon.profil
        self.p_vieuxcon.nom="Vieux con"
        self.p_vieuxcon.promotion="Poufsouffle 1997"
        self.p_vieuxcon.bio="Je suis un vieux con encore en scolarité"
        self.p_vieuxcon.save()

        self.sa_vieuxcon = SocialAccount(user=self.u_vieuxcon,
                                         provider="clipper",
                                         uid="vieuxcon")
        self.sa_vieuxcon.save()
        
        self.vstage1 = Stage(auteur=self.p_vieuxcon, sujet="Oubliettes",
                             date_debut=date(1998, 5, 10),
                             date_fin=date(1998, 8, 26),
                             type_stage="recherche",
                             niveau_scol="M1", public=False)
        self.vstage1.save()
        self.vstage1.matieres.add(self.matiere2)
        alieu1 = AvisLieu(stage=self.vstage1, lieu=self.lieu2,
                          chapo="Pas si mal")
        alieu1.save()
        
        self.client.login(username='vieuxcon', password='vieuxcon')

    """
    Vérifie que les seules fiches de stages visibles sont les siennes ou celles
    publiques
    """
    def test_stage_visibility_scolarite(self):
        testurl = reverse('avisstage:stage',
                          kwargs={'pk':self.cstage1.id})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

        self.assertPageNotFound(reverse('avisstage:stage',
                                        kwargs={'pk':self.cstage2.id}))
        
        testurl = reverse('avisstage:stage',
                          kwargs={'pk':self.vstage1.id})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)


    """
    Vérifie que tous les profils sont visibles
    """
    def test_profil_visibility_scolarite(self):
        testurl = reverse('avisstage:profil',
                          kwargs={'username': self.u_conscrit.username})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)
        self.assertContains(r, "Wingardium Leviosa") # Public
        self.assertNotContains(r, "Avada Kedavra") # Brouillon

        testurl = reverse('avisstage:profil',
                          kwargs={'username': self.u_archi.username})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

        testurl = reverse('avisstage:profil',
                          kwargs={'username': self.u_vieuxcon.username})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

                                   
    """
    Vérifie que la recherche et les autres pages sont accessible
    """
    def test_pages_visibility_scolarite(self):
        testurl = reverse('avisstage:recherche')
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

        testurl = reverse('avisstage:recherche_resultats')
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)
        self.assertContains(r, "Wingardium Leviosa") # Public
        self.assertNotContains(r, "Avada Kedavra") # Brouillon

        testurl = reverse('avisstage:stage_items') + "?ids=" \
                  + ";".join(("%d" % k.id) for k in [self.cstage1,
                                                     self.cstage2,
                                                     self.astage1])
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)
        self.assertContains(r, "Wingardium Leviosa") # Public
        self.assertNotContains(r, "Avada Kedavra") # Brouillon

        testurl = reverse('avisstage:feedback')
        r = self.client.post(testurl, {"objet": "Contact",
                                       "message": "Ceci est un texte"})
        self.assertRedirects(r, reverse('avisstage:index'))

        testurl = reverse('avisstage:moderation')
        r = self.client.get(testurl)
        self.assertRedirects(r, reverse('admin:login')+"?next="+testurl)


    """
    Vérifie que toutes les API sont accessibles et qu'elles ne montrent que les
    stages publics
    """
    def test_api_visibility_scolarite(self):
        testurl = reverse('avisstage:api_dispatch_list',
                          kwargs={"resource_name": "lieu",
                                  "api_name": "v1"})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)
        
        testurl = reverse('avisstage:api_dispatch_list',
                          kwargs={"resource_name": "stage",
                                  "api_name": "v1"})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)
        self.assertContains(r, "Wingardium Leviosa") # Public
        self.assertNotContains(r, "Avada Kedavra") # Brouillon
        
        testurl = reverse('avisstage:api_dispatch_list',
                          kwargs={"resource_name": "profil",
                                  "api_name": "v1"})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

    
    """
    Vérifie que le seul stage modifiable est le sien
    """
    def test_edit_visibility_scolarite(self):
        testurl = reverse('avisstage:stage_edit', kwargs={'pk':self.cstage1.id})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 403)

        testurl = reverse('avisstage:stage_edit', kwargs={'pk':self.astage1.id})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 403)
        
        testurl = reverse('avisstage:stage_edit', kwargs={'pk':self.vstage1.id})
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

        testurl = reverse('avisstage:stage_publication',
                          kwargs={'pk':self.cstage1.id})
        r = self.client.post(testurl, {"publier": True})
        self.assertEqual(r.status_code, 403)

        testurl = reverse('avisstage:stage_publication',
                          kwargs={'pk':self.vstage1.id})
        r = self.client.post(testurl, {"publier": True})
        self.assertRedirects(r, reverse('avisstage:stage',
                                        kwargs={"pk": self.vstage1.id}))
        
        testurl = reverse('avisstage:stage_ajout')
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)
        
        testurl = reverse('avisstage:profil_edit')
        r = self.client.get(testurl)
        self.assertEqual(r.status_code, 200)

        # TODO : test post()