# -*- coding: utf-8 -*-

"""Initialise une base pour les tests de l'API ScoDoc 9

 Création des départements, formations, semestres, étudiants, groupes...

 utilisation:
 1) modifier /opt/scodoc/.env pour indiquer 
    FLASK_ENV=test_api
    FLASK_DEBUG=1 
 
 2) En tant qu'utilisateur scodoc, lancer:
 tools/create_database.sh SCODOC_TEST_API
 flask db upgrade
 flask sco-db-init --erase
 flask init-test-database
 

 3) relancer ScoDoc:
   flask run --host 0.0.0.0

 4) lancer client de test

"""
import datetime
import random
import sys

from app.auth.models import Role, User
from app import models
from app.models import Departement, Formation, FormSemestre, Identite
from app import db
from app.scodoc import (
    sco_cache,
    sco_evaluation_db,
    sco_formations,
    sco_formsemestre_inscriptions,
    sco_groups,
)
from app.scodoc.sco_permissions import Permission
from tools.fakeportal.gen_nomprenoms import nomprenom

random.seed(12345678)  # tests reproductibles

# La formation à utiliser:
FORMATION_XML_FILENAME = "tests/ressources/formations/scodoc_formation_RT_BUT_RT_v1.xml"


def init_departement(acronym: str) -> Departement:
    "Create dept, and switch context into it."
    import app as mapp

    dept = Departement(acronym=acronym)
    db.session.add(dept)
    mapp.set_sco_dept(acronym)
    db.session.commit()
    return dept


def import_formation() -> Formation:
    """Import formation from XML.
    Returns formation_id
    """
    with open(FORMATION_XML_FILENAME) as f:
        doc = f.read()
    # --- Création de la formation
    f = sco_formations.formation_import_xml(doc)
    return Formation.query.get(f[0])


def create_users(dept: Departement) -> tuple:
    """créé les utilisateurs nécessaires aux tests"""
    # Un utilisateur "test" (passwd test) pouvant lire l'API
    user = User(user_name="test", nom="Doe", prenom="John", dept=dept.acronym)
    user.set_password("test")
    db.session.add(user)

    # Le rôle  standard LecteurAPI existe déjà
    role = Role.query.filter_by(name="LecteurAPI").first()
    if role is None:
        print("Erreur: rôle LecteurAPI non existant")
        sys.exit(1)
    perm_api_view = Permission.get_by_name("APIView")
    role.add_permission(perm_api_view)
    db.session.add(role)

    user.add_role(role, None)

    # Un utilisateur "other" n'ayant aucune permission sur l'API
    other = User(user_name="other", nom="Sans", prenom="Permission", dept=dept.acronym)
    other.set_password("other")
    db.session.add(other)

    db.session.commit()
    return user, other


def create_fake_etud(dept: Departement) -> Identite:
    """Créé un faux étudiant et l'insère dans la base."""
    civilite = random.choice(("M", "F", "X"))
    nom, prenom = nomprenom(civilite)
    etud: Identite = Identite(
        civilite=civilite, nom=nom, prenom=prenom, dept_id=dept.id
    )
    db.session.add(etud)
    db.session.commit()
    # créé un étudiant sur deux avec un NIP et INE alphanumérique
    etud.code_nip = f"{etud.id}" if (etud.id % 2) else f"NIP{etud.id}"
    etud.code_ine = f"INE{etud.id}" if (etud.id % 2) else f"{etud.id}"
    db.session.add(etud)
    db.session.commit()
    adresse = models.Adresse(
        etudid=etud.id, email=f"{etud.prenom}.{etud.nom}@example.com"
    )
    db.session.add(adresse)
    admission = models.Admission(etudid=etud.id)
    db.session.add(admission)
    db.session.commit()
    return etud


def create_etuds(dept: Departement, nb=16) -> list:
    "create nb etuds"
    return [create_fake_etud(dept) for _ in range(nb)]


def create_formsemestre(
    formation: Formation, responsable: User, semestre_idx=1
) -> FormSemestre:
    """Create formsemestre and moduleimpls
    responsable: resp. du formsemestre
    """
    formsemestre = FormSemestre(
        dept_id=formation.dept_id,
        semestre_id=semestre_idx,
        titre="Semestre test",
        date_debut=datetime.datetime(2021, 9, 1),
        date_fin=datetime.datetime(2022, 8, 31),
        modalite="FI",
        formation=formation,
    )
    db.session.add(formsemestre)
    db.session.commit()
    # Crée un modulimpl par module de ce semestre:
    for module in formation.modules.filter_by(semestre_id=semestre_idx):
        modimpl = models.ModuleImpl(
            module_id=module.id,
            formsemestre_id=formsemestre.id,
            responsable_id=responsable.id,
        )
        db.session.add(modimpl)
    db.session.commit()
    partition_id = sco_groups.partition_create(
        formsemestre.id, default=True, redirect=False
    )
    _group_id = sco_groups.create_group(partition_id, default=True)
    return formsemestre


def inscrit_etudiants(etuds: list, formsemestre: FormSemestre):
    """Inscrit les etudiants aux semestres et à tous ses modules"""
    for etud in etuds:
        sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
            formsemestre.id,
            etud.id,
            group_ids=[],
            etat="I",
            method="init db test",
        )


def create_evaluations(formsemestre: FormSemestre):
    "creation d'une evaluation dans cahque modimpl du semestre"
    for modimpl in formsemestre.modimpls:
        args = {
            "moduleimpl_id": modimpl.id,
            "jour": None,
            "heure_debut": "8h00",
            "heure_fin": "9h00",
            "description": None,
            "note_max": 20,
            "coefficient": 1.0,
            "visibulletin": True,
            "publish_incomplete": True,
            "evaluation_type": None,
            "numero": None,
        }
        evaluation_id = sco_evaluation_db.do_evaluation_create(**args)


def init_test_database():
    """Appelé par la commande `flask init-test-database`

    Création d'un département et de son contenu pour les tests
    """
    dept = init_departement("TAPI")
    user_lecteur, user_autre = create_users(dept)
    with sco_cache.DeferredSemCacheManager():
        etuds = create_etuds(dept)
        formation = import_formation()
        formsemestre = create_formsemestre(formation, user_lecteur)
        create_evaluations(formsemestre)
        inscrit_etudiants(etuds, formsemestre)
    # à compléter
    # - groupes
    # - absences
    # - notes
    # - décisions de jury
    # ...