##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
# See LICENSE
##############################################################################

"""Liste simple d'étudiants
"""

from flask import g, url_for
from app import log
from app.models import FormSemestre, Identite, Justificatif
from app.tables import table_builder as tb
import app.scodoc.sco_assiduites as scass
from app.scodoc import sco_preferences
from app.scodoc import sco_utils as scu


class TableAssi(tb.Table):
    """Table listant les statistiques d'assiduité des étudiants
    L'id de la ligne est etuid, et le row stocke etud.
    """

    def __init__(
        self,
        etuds: list[Identite] = None,
        dates: tuple[str, str] = None,
        formsemestre: FormSemestre = None,
        **kwargs,
    ):
        self.rows: list["RowEtud"] = []  # juste pour que VSCode nous aide sur .rows
        classes = ["gt_table"]
        self.dates = [str(dates[0]) + "T00:00", str(dates[1]) + "T23:59"]
        self.formsemestre = formsemestre
        super().__init__(
            row_class=RowAssi,
            classes=classes,
            **kwargs,
            with_foot_titles=False,
        )
        self.add_etuds(etuds)

    def add_etuds(self, etuds: list[Identite]):
        "Ajoute des étudiants à la table"
        for etud in etuds:
            row = self.row_class(self, etud)
            row.add_etud_cols()
            self.add_row(row)


class RowAssi(tb.Row):
    "Ligne de la table assiduité"

    # pour le moment très simple, extensible (codes, liens bulletins, ...)
    def __init__(self, table: TableAssi, etud: Identite, *args, **kwargs):
        # Etat de l'inscription au formsemestre
        if "classes" not in kwargs:
            kwargs["classes"] = []
        try:
            inscription = table.formsemestre.etuds_inscriptions[etud.id]
            if inscription.etat == scu.DEMISSION:
                kwargs["classes"].append("etuddem")
        except KeyError:
            log(f"RowAssi: etudid {etud.id} non inscrit à {table.formsemestre.id}")
            kwargs["classes"].append("non_inscrit")  # ne devrait pas arriver !

        super().__init__(table, etud.id, *args, **kwargs)
        self.etud = etud
        self.dates = table.dates

    def add_etud_cols(self):
        """Ajoute les colonnes"""
        etud = self.etud
        self.table.group_titles.update(
            {
                "etud_codes": "Codes",
                "identite_detail": "",
                "identite_court": "",
            }
        )

        bilan_etud = url_for(
            "assiduites.bilan_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id
        )
        self.add_cell(
            "nom_disp",
            "Nom",
            etud.nom_disp(),
            "etudinfo",
            attrs={"id": str(etud.id)},
            data={"order": etud.sort_key},
            target=bilan_etud,
            target_attrs={"class": "discretelink"},
        )
        self.add_cell(
            "prenom",
            "Prénom",
            etud.prenom_str,
            "etudinfo",
            attrs={"id": str(etud.id)},
            data={"order": etud.sort_key},
            target=bilan_etud,
            target_attrs={"class": "discretelink"},
        )
        stats = self._get_etud_stats(etud)
        for key, value in stats.items():
            self.add_cell(key, value[0], f"{value[1] - value[2]}", "assi_stats")
            if key != "present":
                self.add_cell(
                    key + "_justi",
                    value[0] + " Justifiées",
                    f"{value[2]}",
                    "assi_stats",
                )

        compte_justificatifs = scass.filter_by_date(
            etud.justificatifs, Justificatif, self.dates[0], self.dates[1]
        )

        compte_justificatifs_att = compte_justificatifs.filter(Justificatif.etat == 2)

        self.add_cell(
            "justificatifs_att",
            "Justificatifs en Attente",
            f"{compte_justificatifs_att.count()}",
        )
        self.add_cell(
            "justificatifs", "Justificatifs", f"{compte_justificatifs.count()}"
        )

    def _get_etud_stats(self, etud: Identite) -> dict[str, list[str, float, float]]:
        """
        Renvoie le comptage (dans la métrique du département) des différents états d'assiduité d'un étudiant

        Returns :
            {
                "<etat>" : [<Etat version lisible>, <nb total etat>, <nb just etat>]
            }

        """

        # Préparation du retour
        retour: dict[str, tuple[str, float, float]] = {
            "absent": ["Absences", 0.0, 0.0],
            "retard": ["Retards", 0.0, 0.0],
            "present": ["Présences", 0.0, 0.0],
        }

        # Récupération de la métrique du département
        assi_metric = scu.translate_assiduites_metric(
            sco_preferences.get_preference("assi_metrique", dept_id=g.scodoc_dept_id),
        )

        compte_etat: dict[str, dict] = scass.get_assiduites_stats(
            assiduites=etud.assiduites,
            metric=assi_metric,
            filtered={
                "date_debut": self.dates[0],
                "date_fin": self.dates[1],
                "etat": "absent,present,retard",  # pour tout compter d'un coup
                "split": 1,  # afin d'avoir la division des stats en état, etatjust, etatnonjust
            },
        )

        # Pour chaque état on met à jour les valeurs de retour
        for etat, valeur in retour.items():
            valeur[1] = compte_etat[etat][assi_metric]
            if etat != "present":
                valeur[2] = compte_etat[etat]["justifie"][assi_metric]
        return retour


def etuds_sorted_from_ids(etudids) -> list[Identite]:
    "Liste triée d'etuds à partir d'une collections d'etudids"
    etuds = [Identite.get_etud(etudid) for etudid in etudids]
    return sorted(etuds, key=lambda etud: etud.sort_key)
