from django.contrib.staticfiles.testing import StaticLiveServerTestCase

from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.webdriver import WebDriver
from recuperateur_reseau_viaire.models import Graph_viaire_ville_information, Ville, Rassemblement_ville
import re
import random

class view_indexTests(StaticLiveServerTestCase):

    selenium = None

    @classmethod
    def setUpClass(cls):
        """
        Le but de cette méthode est d'initialiser selenium avant le début des tests de la classe

        """
        super().setUpClass()
        cls.selenium = WebDriver()
        cls.selenium.implicitly_wait(10)

    @classmethod
    def tearDownClass(cls):
        """
        Le but de cette méthode est de fermer selenium à la fin des tests de la classe
        """
        cls.selenium.quit()
        super().tearDownClass()

    def setUp(self) -> None:
        """
        Le but de cette méthode est que selenium soit dans l'index du site à chaque test
        """
        self.nom_ville_test_a = "commune"
        self.nom_ville_test_b = "ville"

        def ajoute_ville_et_gvvi(nom_ville):
            """
            Cette méthoe permet de créer dans la base de donnée une ville de nom nom_ville et ses informations associées
            dans la table Graph_viaire_ville_information
            :param nom_ville: le nom de la ville que nous voulons ajouter
            :return:
            """
            Ville.objects.create(ville_nom=nom_ville)
            valeur = random.randint(5, 10)
            Graph_viaire_ville_information.objects.create(gvvi_cout=valeur, gvvi_robustesse=valeur,
                                                          gvvi_d2_correlation_dimension=valeur,
                                                          gvvi_d1_information_dimension=valeur,
                                                          gvvi_d0_fractal_capacite_dimension=valeur,
                                                          gvvi_longueur_moyenne_rues=valeur, gvvi_tree_vs_complete_graph=valeur,
                                                          gvvi_org_plan_vs_organized=valeur, gvvi_connectivity=valeur,
                                                          gvvi_degre_moyen=valeur, gvvi_diametre=valeur, gvvi_nb_intersection=valeur,
                                                          ville=Ville.objects.get(ville_nom=nom_ville))

        # création d'une instance de Ville
        ajoute_ville_et_gvvi(self.nom_ville_test_a)
        ajoute_ville_et_gvvi(self.nom_ville_test_b)
        ville = "ville_englobe"
        Ville.objects.create(ville_nom=ville)
        Rassemblement_ville.objects.create(ville_englobante=Ville.objects.get(ville_nom=self.nom_ville_test_a),
                                           ville=Ville.objects.get(ville_nom=self.nom_ville_test_b))
        Rassemblement_ville.objects.create(ville_englobante=Ville.objects.get(ville_nom=self.nom_ville_test_a),
                                           ville=Ville.objects.get(ville_nom=ville))
        self.selenium.get('%s%s' % (self.live_server_url, '/recuperateur_reseau_viaire/'))

    def test_index_bouton_telechargement_ville(self):
        """
        Cette mthode test le bouton de téléchargement de la page index
        """
        self.selenium.find_element(
            By.LINK_TEXT, "Ajout"
        ).click()
        self.assertTrue(self.selenium.current_url.endswith("/recuperateur_reseau_viaire/telecharge_liste_commune"))

    def test_index_bouton_exporter(self):
        """
        Cette méthode va tester le bouton d'exportation de la base de donnée
        """
        self.selenium.find_element(
            By.LINK_TEXT, 'exporter'
        ).click()
        self.assertTrue(self.selenium.current_url.endswith("/recuperateur_reseau_viaire/export/"))

    def test_index_bouton_update_plusieurs_villes_sans_cocher_de_case(self):
        """
        Cette méthode va tester le bouton update qui permet de mettre à jour plusieurs lignes sans cocher de case
        """
        self.selenium.find_element(
            By.XPATH, '//button[@value="update"]'
        ).click()
        self.assertTrue(self.selenium.current_url.
                        find("/recuperateur_reseau_viaire/?bouton=update&csrfmiddlewaretoken=") != -1)
        regexp = re.compile(r'update=\d+')
        self.assertTrue(regexp.search(self.selenium.current_url) is None)
        self.assertEqual(self.selenium.find_element(By.CSS_SELECTOR, "h1").text, "Recuperateur de graph OpenStreetMap")

    def test_index_bouton_update_cocher_toutes_les_villes(self):
        """
        Cette méthode a pour but de cocher toutes les lignes et ensuite d'appuyer sur le bouton update
        """
        self.selenium.find_element(
            By.XPATH, '//input[@onclick="check_toutes_les_autres(this);"]'
        ).click()
        self.selenium.find_element(
            By.XPATH, '//button[@value="update"]'
        ).click()
        self.assertTrue(self.selenium.current_url.
                        find("/recuperateur_reseau_viaire/?bouton=update&csrfmiddlewaretoken=") != -1)
        regexp = re.compile(r'update=\d+')
        self.assertTrue(regexp.search(self.selenium.current_url) is not None)
        self.assertEqual(self.selenium.find_element(By.CSS_SELECTOR, "h1").text, "Modification donnée graphe viaire")

    def test_index_bouton_update_cocher_ligne_par_ligne(self):
        """
        Cette méthode test la mise à jour de ville en cochant les lignes une par une
        """
        liste_case = self.selenium.find_elements(
            By.CSS_SELECTOR, "#update"
        )
        valeur_cases = []
        for case in liste_case:
            case.click()
            valeur_cases.append(case.get_attribute("value"))
        self.selenium.find_element(
            By.XPATH, '//button[@value="update"]'
        ).click()
        self.assertTrue(self.selenium.current_url.
                        find("/recuperateur_reseau_viaire/?bouton=update&csrfmiddlewaretoken=") != -1)
        regexp = re.compile(r'update=\d+')
        # le nombre de cases coché et le bon
        self.assertTrue(regexp.search(self.selenium.current_url) is not None and len(regexp.findall(self.selenium.current_url)) == len(liste_case))
        # les valeurs envoyées cochées sont les bonnes
        valeurs_envoyees = [valeur[valeur.index("=") + 1:] for valeur in regexp.findall(self.selenium.current_url)]
        self.assertEqual(valeurs_envoyees, valeur_cases)
        #le titre de la page est celui du formulaire de modification
        self.assertEqual(self.selenium.find_element(By.CSS_SELECTOR, "h1").text, "Modification donnée graphe viaire")

    def test_lien_update_une_seul_table(self):
        """
        Cette méthode a pour but de tester le lien en bout de ligne de la table dans la page principale
        """
        liste_choix = self.selenium.find_elements(By.LINK_TEXT, "Update")
        for choix_ligne in range(len(liste_choix)):
            # à chaque changement de page il faut récupérer les boutons
            liste_choix = self.selenium.find_elements(By.LINK_TEXT, "Update")
            # il faut récupérer la chaine de caractère du lien avant de cliquer
            lien_choix = liste_choix[choix_ligne].get_attribute("href").split("/")[-1]
            liste_choix[choix_ligne].click()
            gvvi_instance = Graph_viaire_ville_information.objects.get(id=lien_choix)
            for sgbd_var in dir(Graph_viaire_ville_information):
                if sgbd_var.startswith("gvvi_"):
                    self.assertEqual(float(self.selenium.find_element(By.NAME, sgbd_var).get_attribute("value")), getattr(gvvi_instance, sgbd_var))
            self.assertEqual(self.selenium.find_element(By.NAME, "gvvi_nom").get_attribute("value"), gvvi_instance.ville.ville_nom)
            # on test la présence des noms de villes englobées
            id_villes_englobees_sgbd = [rassemblement_ville_instance.ville.ville for rassemblement_ville_instance in Rassemblement_ville.objects.filter(ville_englobante=gvvi_instance.ville)]
            if len(id_villes_englobees_sgbd) != 0:
                id_ville_englobees_checked_box = [int(ville_englobees.get_attribute("value")) for ville_englobees in self.selenium.find_elements(By.NAME, "ville_englobe")]
                self.assertEqual(id_villes_englobees_sgbd, id_ville_englobees_checked_box)
            # on retourne à la page principale
            self.selenium.get('%s%s' % (self.live_server_url, '/recuperateur_reseau_viaire/'))

    def test_lien_suppression_une_seule_ligne(self):
        """
        Cette méthode test le lien de suppression d'une ligne d'une table
        """
        liste_choix = self.selenium.find_elements(By.LINK_TEXT, "Delete")
        gvvi_instance_liste = Graph_viaire_ville_information.objects.all()
        for choix_ligne in range(len(liste_choix)):
            self.assertTrue(liste_choix[choix_ligne].get_attribute("href").endswith("/graph_id_delete/" + gvvi_instance_liste[choix_ligne].id.__str__()))