# -*- pole: python -*-
# -*- coding: utf-8 -*-

##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2024 Emmanuel Viennet.  All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#   Emmanuel Viennet      emmanuel.viennet@viennet.net
#
##############################################################################

##############################################################################
#  Module "Avis de poursuite d'étude"
#  conçu et développé par Cléo Baras (IUT de Grenoble)
##############################################################################


"""
Created on Thu Sep  8 09:36:33 2016

@author: barasc
"""

import pandas as pd

from app.models import Identite
from app.pe.moys import pe_moytag

TAGS_RESERVES = ["but"]

CHAMPS_ADMINISTRATIFS = ["Civilité", "Nom", "Prénom"]


class TableTag(object):
    def __init__(self):
        """Classe centralisant différentes méthodes communes aux
        SemestreTag, TrajectoireTag, AggregatInterclassTag
        """
        # Les étudiants
        # self.etuds: list[Identite] = None  # A venir
        """Les étudiants"""
        # self.etudids: list[int] = {}
        """Les etudids"""

    def add_etuds(self, etuds: list[Identite]):
        """Mémorise les informations sur les étudiants

        Args:
            etuds: la liste des identités de l'étudiant
        """
        # self.etuds = etuds
        self.etudids = list({etud.etudid for etud in etuds})

    def get_all_significant_tags(self):
        """Liste des tags de la table, triée par ordre alphabétique,
        extraite des clés du dictionnaire ``moyennes_tags``, en ne
        considérant que les moyennes ayant des notes.

        Returns:
            Liste de tags triés par ordre alphabétique
        """
        tags = []
        tag: str = ""
        moytag: pe_moytag.MoyennesTag = None
        for tag, moytag in self.moyennes_tags.items():
            if moytag.has_notes():
                tags.append(tag)
        return sorted(tags)

    def to_df(
        self,
        administratif=True,
        aggregat=None,
        tags_cibles=None,
        cohorte=None,
        options={"min_max_moy": True},
    ) -> pd.DataFrame:
        """Renvoie un dataframe listant toutes les données
        des moyennes/classements/nb_inscrits/min/max/moy
        des étudiants aux différents tags.

        tags_cibles limitent le dataframe aux tags indiqués
        type_colonnes indiquent si les colonnes doivent être passées en multiindex

        Args:
            administratif: Indique si les données administratives sont incluses
            aggregat: l'aggrégat représenté
            tags_cibles: la liste des tags ciblés
            cohorte: la cohorte représentée
        Returns:
            Le dataframe complet de synthèse
        """
        # Les tags visés
        tags_tries = self.get_all_significant_tags()
        if not tags_cibles:
            tags_cibles = tags_tries
        tags_cibles = sorted(tags_cibles)

        # Les tags visés avec des notes

        # Les étudiants visés
        if administratif:
            df = df_administratif(self.etuds, aggregat=aggregat, cohorte=cohorte)
        else:
            df = pd.DataFrame(index=self.etudids)

        if not self.is_significatif():
            return df

        # Ajout des données par tags
        for tag in tags_cibles:
            if tag in self.moyennes_tags:
                moy_tag_df = self.moyennes_tags[tag].to_df(
                    aggregat=aggregat, cohorte=cohorte, options=options
                )
                df = df.join(moy_tag_df)

        # Tri par nom, prénom
        if administratif:
            colonnes_tries = [
                _get_champ_administratif(champ, aggregat=aggregat, cohorte=cohorte)
                for champ in CHAMPS_ADMINISTRATIFS[1:]
            ]  # Nom + Prénom
            df = df.sort_values(by=colonnes_tries)
        return df

    def has_etuds(self):
        """Indique si un tabletag contient des étudiants"""
        return len(self.etuds) > 0

    def is_significatif(self):
        """Indique si une tabletag a des données"""
        # A des étudiants
        if not self.etuds:
            return False
        # A des tags avec des notes
        tags_tries = self.get_all_significant_tags()
        if not tags_tries:
            return False
        return True


def _get_champ_administratif(champ, aggregat=None, cohorte=None):
    """Pour un champ donné, renvoie l'index (ou le multindex)
    à intégrer au dataframe"""
    liste = []
    if aggregat != None:
        liste += [aggregat]
    liste += ["Administratif", "Identité"]
    if cohorte != None:
        liste += [champ]
    liste += [champ]
    return "|".join(liste)


def df_administratif(
    etuds: list[Identite], aggregat=None, cohorte=None
) -> pd.DataFrame:
    """Renvoie un dataframe donnant les données administratives
    des étudiants du TableTag

    Args:
        etuds: Identité des étudiants générant les données administratives
    """
    identites = {etud.etudid: etud for etud in etuds}

    donnees = {}
    etud: Identite = None
    for etudid, etud in identites.items():
        data = {
            CHAMPS_ADMINISTRATIFS[0]: etud.civilite_str,
            CHAMPS_ADMINISTRATIFS[1]: etud.nom,
            CHAMPS_ADMINISTRATIFS[2]: etud.prenom_str,
        }
        donnees[etudid] = {
            _get_champ_administratif(champ, aggregat, cohorte): data[champ]
            for champ in CHAMPS_ADMINISTRATIFS
        }

    colonnes = [
        _get_champ_administratif(champ, aggregat, cohorte)
        for champ in CHAMPS_ADMINISTRATIFS
    ]

    df = pd.DataFrame.from_dict(donnees, orient="index", columns=colonnes)
    df = df.sort_values(by=colonnes[1:])
    return df
