from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.contrib.auth.models import User

from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys

from .models import Eleves, Inventaire, Materiel

import os

# Create your tests here.

class TestAvecBDD(StaticLiveServerTestCase):
    """
    Tests qui nécessitent de déployer une base de données de tests
    """

    fixtures = ['fixtures/test_data.json']
    
    credentials = {
        'username': 'testuser',
        'password': 'secret'
    }
    
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.service = ChromeService(executable_path="/usr/bin/chromedriver")
        options = Options()
        cls.ui_visible = True
        if not os.environ.get("VIEW_SELENIUM") == "1":
            options.add_argument('--headless')
            print("WARNING: to display Chrome's UI, set VIEW_SELENIUM=1")
            cls.ui_visible = False
        cls.selenium = webdriver.Chrome(
            options = options, service = cls.service)
        cls.selenium.implicitly_wait(10)
        return

    def setUp(self):
        """
        Ajoute un utilisateur 'testuser'
        """
        StaticLiveServerTestCase.setUp(self)
        u = User.objects.create_user(**self.credentials)
        u.is_staff = True # important, car le login est à /admin/login
        u.save()
        return
        
    @classmethod
    def tearDownClass(cls):
        cls.selenium.quit()
        super().tearDownClass()
        return
    
    def test_inventaire(self):
        # nombre total de livres
        livres = Inventaire.objects.all()
        self.assertGreater(
            len(livres), 3000, "on attendrait plus de 3000 livres")
        # dont « non prêtés »
        self.assertEqual(
            Inventaire.non_pretes_qs().count(),
            1983, "on attendrait 1983 livres non prêtés")
        # dont « prêtés »
        self.assertEqual(
            Inventaire.pretes_qs().count(),
            1933, "on attendrait 1933 livres prêtés")
        # manuels "Physique Chimie 2nde" prêtés
        ref = Materiel.objects.get(titre="Physique Chimie 2nde")
        qs = Inventaire.pretes_qs()
        qs = qs.filter(materiel = ref)
        self.assertEqual(
            qs.count(), 59,
            "On attendrait 59 livres de Physique Chimie 2nde")
        # À qui est ce livre ?
        liv = Inventaire.objects.get(id = 227)
        self.assertEqual(
            liv.materiel.titre, "Team deutsch 2nde",
            "le titre du livre n°227 devrait être Team deutsch 2nde")
        e = liv.actuellement_a()
        self.assertIs(
            e, None, "le livre Team deutsch 2nde n° 227 ne devrait pas prêté")
        liv = Inventaire.objects.get(id = 667)
        self.assertEqual(
            liv.materiel.titre, "Gammar training time 2nde",
            "le titre du livre n°667 devrait être Gammar training time 2nde")
        e = liv.actuellement_a()
        f = Eleves.objects.get(NomPrenomEleve = "Bifidus Celestine")
        self.assertEqual(
            e.id, f.id,
            "le livre Gammar training time 2nde n° 667 devrait être prêté à " +
            "Bifidus Celestine")
        return
    
    def test_avec_login(self):
        """
        - force l'interface en français et vérifie les traductions
        - force l'interface en espagnol et vérifie les traductions
        - login sous l'identité de 'testuser'
        """

        """
        I18N et L10N
        ============
        
        Sur la page '/apropos', qui ne requiert pas d'être logé, vérifions
        si un changement de langue va modifier par exemple le titre d'un
        bouton.
        """
        self.selenium.get(f"{self.live_server_url}/apropos")
        # choix du français
        self.selenium.find_element(
            By.CSS_SELECTOR, "#language-fr img").click()
        # un peu d'attente
        ActionChains(self.selenium).pause(.5).perform()
        img = self.selenium.find_element(By.CSS_SELECTOR, '#aide img')
        self.assertEqual(img.get_attribute("title"), "Aide contextuelle")
        # choix de l'espagnol
        img_es = self.selenium.find_element(
            By.CSS_SELECTOR, "#language-es img").click()
        # un peu d'attente
        ActionChains(self.selenium).pause(.5).perform()
        img = self.selenium.find_element(By.CSS_SELECTOR, '#aide img')
        self.assertEqual(img.get_attribute("title"), "Ayuda contextual")

        # retour au français
        self.selenium.find_element(
            By.CSS_SELECTOR, "#language-fr img").click()
        # un peu d'attente
        ActionChains(self.selenium).pause(.5).perform()
        img = self.selenium.find_element(By.CSS_SELECTOR, '#aide img')
        self.assertEqual(img.get_attribute("title"), "Aide contextuelle")

        """
        Login en tant que 'testuser'
        """
        self.selenium.find_element(By.CSS_SELECTOR, '#id_username')\
                     .send_keys(self.credentials['username'])
        self.selenium.find_element(By.CSS_SELECTOR, '#id_password')\
                     .send_keys(self.credentials['password'])
        form = self.selenium.find_element(By.TAG_NAME, "form")
        valid = form.find_elements(By.TAG_NAME, "input")[-1]
        valid.click();
        #un peu d'attente
        ActionChains(self.selenium).pause(.5).perform()

        """
        Fonctionnement de l'auto-complétion de nom d'utilisateur dans la
        page '/prets'
        """
        self.selenium.get(f"{self.live_server_url}/prets")
        nomprenom = self.selenium.find_element(By.ID, "nomprenom")
        ActionChains(self.selenium)\
            .send_keys_to_element(nomprenom, "age")\
            .perform()
        #un peu d'attente
        ActionChains(self.selenium).pause(.5).perform()
        divs = self.selenium.find_elements(By.CSS_SELECTOR, "#ui-id-1 div")
        self.assertEqual(
            {d.text for d in divs},
            {
                'Vagennius Manël',
                'Trodéxès de Collagène Nacer',
                'Agecanonix Suzie',
                'Trodéxès de Collagène Gael',
            }
        )
        # un va cliquer sur 'Trodéxès de Collagène Gael'
        tcg = [d for d in divs if d.text =='Trodéxès de Collagène Gael'][0]
        tcg.click()
        #un peu d'attente
        ActionChains(self.selenium).pause(.5).perform()
        # vérification du nombre de livres prêtés
        lignes = self.selenium.find_elements(
            By.CSS_SELECTOR, "#tableau_prets tr")
        self.assertEqual(len(lignes), 11)
        # on va prêter le livre de math '12341' à Trodéxès de Collagène Gael
        # celui-ci est en surnombre
        l_input = self.selenium.find_element(By.CSS_SELECTOR, "#codelivre")
        l_input.send_keys("12341")
        l_input.send_keys(Keys.RETURN)
        #un peu d'attente
        ActionChains(self.selenium).pause(.5).perform()
        # on va cliquer "non" (on doit entendre un son d'avertissement)
        self.selenium.find_elements(By.CSS_SELECTOR, ".ui-button")[0].click()
        #un peu d'attente
        ActionChains(self.selenium).pause(.5).perform()
        # on prête le livre pour de bon
        self.selenium.find_elements(
            By.CSS_SELECTOR, ".actionbuttons")[0].click()
        # un peu plus d'attente : un message apparaît puis disparaît
        ActionChains(self.selenium).pause(6).perform()
        # vérification du nombre de livres prêtés
        # contrairement à Firefox, selenium+chrome ne conserve pas
        # le contenu du champ "nomprenom" quand la page est rafraîchie
        self.selenium.find_element(By.ID, "nomprenom")\
                     .send_keys("Trodéxès de Collagène Gael\n")
        #un peu d'attente
        ActionChains(self.selenium).pause(.5).perform()
        lignes = self.selenium.find_elements(
            By.CSS_SELECTOR, "#tableau_prets tr")
        self.assertEqual(len(lignes), 12)

        # vérifions le nombre d'élèves dans la même classe
        meme_classe_lignes = self.selenium.find_elements(
            By.CSS_SELECTOR, ".liste-scroll-y tr")
        self.assertEqual(len(meme_classe_lignes), 30)
        # vérifions si la ligne de Trodéxès de Collagène Gael est
        # sélectionnée en gris
        td_eleve = self.selenium.find_elements(
            By.CSS_SELECTOR, ".liste-scroll-y tr td.meme-eleve")[0]
        self.assertEqual(td_eleve.text, "Trodéxès de Collagène Gael")

        if self.ui_visible:
            #un peu d'attente avant de tout effacer
            ActionChains(self.selenium).pause(6).perform()
        
