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

##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2022 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
#
##############################################################################

"""Génération du bulletin en format XML / compatibilité ScoDoc 7

 => exporte quelques résultats BUT dans le format des anciens bulletins XML ScoDoc 7
 afin d'avoir un affichage acceptable sur les ENT anciens.

Les plate-formes modernes utilisent uniquement la version JSON (but/bulletin_but.py)
"""


import datetime
from xml.etree import ElementTree
from xml.etree.ElementTree import Element

from app import log
from app.but import bulletin_but
from app.models import FormSemestre, Identite
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc import sco_abs
from app.scodoc import sco_codes_parcours
from app.scodoc import sco_edit_ue
from app.scodoc import sco_etud
from app.scodoc import sco_photos
from app.scodoc import sco_preferences
from app.scodoc import sco_xml


def bulletin_but_xml_compat(
    formsemestre_id,
    etudid,
    doc=None,  # XML document
    force_publishing=False,
    xml_nodate=False,
    xml_with_decisions=False,  # inclue les decisions même si non publiées
    version="long",
) -> str:
    """Bulletin XML au format ScoDoc 7, avec informations "BUT" """
    from app.scodoc import sco_bulletins

    log(
        "bulletin_but_xml_compat( formsemestre_id=%s, etudid=%s )"
        % (formsemestre_id, etudid)
    )
    formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
    etud: Identite = Identite.query.get_or_404(etudid)
    results = bulletin_but.ResultatsSemestreBUT(formsemestre)
    nb_inscrits = results.get_inscriptions_counts()[scu.INSCRIT]
    # etat_inscription = etud.inscription_etat(formsemestre.id)
    etat_inscription = results.formsemestre.etuds_inscriptions[etudid].etat
    if (not formsemestre.bul_hide_xml) or force_publishing:
        published = 1
    else:
        published = 0
    if xml_nodate:
        docdate = ""
    else:
        docdate = datetime.datetime.now().isoformat()
    el = {
        "etudid": str(etudid),
        "formsemestre_id": str(formsemestre_id),
        "date": docdate,
        "publie": str(published),
    }
    if formsemestre.etapes:
        el["etape_apo"] = formsemestre.etapes[0].etape_apo or ""
        n = 2
        for et in formsemestre.etapes[1:]:
            el["etape_apo" + str(n)] = et.etape_apo or ""
            n += 1
    x = Element("bulletinetud", **el)
    if doc:
        is_appending = True
        doc.append(x)
    else:
        is_appending = False
        doc = x
    # Infos sur l'etudiant
    doc.append(
        Element(
            "etudiant",
            etudid=str(etudid),
            code_nip=etud.code_nip or "",
            code_ine=etud.code_ine or "",
            nom=scu.quote_xml_attr(etud.nom),
            prenom=scu.quote_xml_attr(etud.prenom),
            civilite=scu.quote_xml_attr(etud.civilite_str),
            sexe=scu.quote_xml_attr(etud.civilite_str),  # compat
            photo_url=scu.quote_xml_attr(sco_photos.get_etud_photo_url(etud.id)),
            email=scu.quote_xml_attr(etud.get_first_email() or ""),
            emailperso=scu.quote_xml_attr(etud.get_first_email("emailperso") or ""),
        )
    )
    # Disponible pour publication ?
    if not published:
        return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(
            scu.SCO_ENCODING
        )  # stop !

    if etat_inscription == scu.INSCRIT:
        # Moyenne générale:
        doc.append(
            Element(
                "note",
                value=scu.fmt_note(results.etud_moy_gen[etud.id]),
                min=scu.fmt_note(results.etud_moy_gen.min()),
                max=scu.fmt_note(results.etud_moy_gen.max()),
                moy=scu.fmt_note(results.etud_moy_gen.mean()),  # moyenne des moy. gen.
            )
        )
        rang = 0  # XXX TODO rang de l'étudiant selon la moy gen indicative
        # valeur du bonus sport
        if results.bonus is not None:
            bonus = results.bonus[etud.id]
        else:
            bonus = 0
        doc.append(Element("rang", value=str(rang), ninscrits=str(nb_inscrits)))
        # XXX TODO: ajouter "rang_group" : rangs dans les partitions
        doc.append(Element("note_max", value="20"))  # notes toujours sur 20
        doc.append(Element("bonus_sport_culture", value=str(bonus)))
        # Liste les UE / modules /evals
        for ue in results.ues:  # avec bonus
            rang_ue = 0  # XXX TODO rang de l'étudiant dans cette UE
            nb_inscrits_ue = (
                nb_inscrits  # approx: compliqué de définir le "nb d'inscrit à une UE"
            )
            x_ue = Element(
                "ue",
                id=str(ue.id),
                numero=scu.quote_xml_attr(ue.numero),
                acronyme=scu.quote_xml_attr(ue.acronyme or ""),
                titre=scu.quote_xml_attr(ue.titre or ""),
                code_apogee=scu.quote_xml_attr(ue.code_apogee or ""),
            )
            doc.append(x_ue)
            if ue.type != sco_codes_parcours.UE_SPORT:
                v = results.etud_moy_ue[ue.id][etud.id]
                vmin = results.etud_moy_ue[ue.id].min()
                vmax = results.etud_moy_ue[ue.id].max()
            else:
                v = results.bonus or 0.0
                vmin = vmax = 0.0
            x_ue.append(
                Element(
                    "note",
                    value=scu.fmt_note(v),
                    min=scu.fmt_note(vmin),
                    max=scu.fmt_note(vmax),
                )
            )
            x_ue.append(Element("ects", value=str(ue.ects if ue.ects else 0)))
            x_ue.append(Element("rang", value=str(rang_ue)))
            x_ue.append(Element("effectif", value=str(nb_inscrits_ue)))
            # Liste les modules rattachés à cette UE
            for modimpl in results.formsemestre.modimpls:
                # Liste ici uniquement les modules rattachés à cette UE
                if modimpl.module.ue.id == ue.id:
                    # mod_moy = scu.fmt_note(results.etud_moy_ue[ue.id][etud.id])
                    try:
                        coef = results.modimpl_coefs_df[modimpl.id][ue.id]
                    except KeyError:
                        coef = 0.0
                    x_mod = Element(
                        "module",
                        id=str(modimpl.id),
                        code=str(modimpl.module.code or ""),
                        coefficient=str(coef),
                        numero=str(modimpl.module.numero or 0),
                        titre=scu.quote_xml_attr(modimpl.module.titre or ""),
                        abbrev=scu.quote_xml_attr(modimpl.module.abbrev or ""),
                        code_apogee=scu.quote_xml_attr(
                            modimpl.module.code_apogee or ""
                        ),
                    )
                    # XXX TODO  rangs et effectifs
                    # --- notes de chaque eval:
                    if version != "short":
                        for e in modimpl.evaluations:
                            if e.visibulletin or version == "long":
                                x_eval = Element(
                                    "evaluation",
                                    jour=e.jour.isoformat() if e.jour else "",
                                    heure_debut=e.heure_debut.isoformat()
                                    if e.heure_debut
                                    else "",
                                    heure_fin=e.heure_fin.isoformat()
                                    if e.heure_debut
                                    else "",
                                    coefficient=str(e.coefficient),
                                    # pas les poids en XML compat
                                    evaluation_type=str(e.evaluation_type),
                                    description=scu.quote_xml_attr(e.description),
                                    # notes envoyées sur 20, ceci juste pour garder trace:
                                    note_max_origin=str(e.note_max),
                                )
                                x_mod.append(x_eval)
                                try:
                                    x_eval.append(
                                        Element(
                                            "note",
                                            value=scu.fmt_note(
                                                results.modimpls_results[
                                                    e.moduleimpl_id
                                                ].evals_notes[e.id][etud.id],
                                                note_max=e.note_max,
                                            ),
                                        )
                                    )
                                except KeyError:
                                    x_eval.append(
                                        Element("note", value="", note_max="")
                                    )

                                # XXX TODO: Evaluations incomplètes ou futures: XXX
            # XXX TODO UE capitalisee (listee seulement si meilleure que l'UE courante)

    # --- Absences
    if sco_preferences.get_preference("bul_show_abs", formsemestre_id):
        nbabs, nbabsjust = formsemestre.get_abs_count(etud.id)
        doc.append(Element("absences", nbabs=str(nbabs), nbabsjust=str(nbabsjust)))

    # -------- LA SUITE EST COPIEE SANS MODIF DE sco_bulletins_xml.py ---------
    # TODO : refactoring

    # --- Decision Jury
    if (
        sco_preferences.get_preference("bul_show_decision", formsemestre_id)
        or xml_with_decisions
    ):
        infos, dpv = sco_bulletins.etud_descr_situation_semestre(
            etudid,
            formsemestre_id,
            format="xml",
            show_uevalid=sco_preferences.get_preference(
                "bul_show_uevalid", formsemestre_id
            ),
        )
        x_situation = Element("situation")
        x_situation.text = scu.quote_xml_attr(infos["situation"])
        doc.append(x_situation)
        if dpv:
            decision = dpv["decisions"][0]
            etat = decision["etat"]
            if decision["decision_sem"]:
                code = decision["decision_sem"]["code"] or ""
            else:
                code = ""
            if (
                decision["decision_sem"]
                and "compense_formsemestre_id" in decision["decision_sem"]
            ):
                doc.append(
                    Element(
                        "decision",
                        code=code,
                        etat=str(etat),
                        compense_formsemestre_id=str(
                            decision["decision_sem"]["compense_formsemestre_id"] or ""
                        ),
                    )
                )
            else:
                doc.append(Element("decision", code=code, etat=str(etat)))

            if decision[
                "decisions_ue"
            ]:  # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
                for ue_id in decision["decisions_ue"].keys():
                    ue = sco_edit_ue.ue_list({"ue_id": ue_id})[0]
                    doc.append(
                        Element(
                            "decision_ue",
                            ue_id=str(ue["ue_id"]),
                            numero=scu.quote_xml_attr(ue["numero"]),
                            acronyme=scu.quote_xml_attr(ue["acronyme"]),
                            titre=scu.quote_xml_attr(ue["titre"]),
                            code=decision["decisions_ue"][ue_id]["code"],
                        )
                    )

            for aut in decision["autorisations"]:
                doc.append(
                    Element(
                        "autorisation_inscription", semestre_id=str(aut["semestre_id"])
                    )
                )
        else:
            doc.append(Element("decision", code="", etat="DEM"))
    # --- Appreciations
    cnx = ndb.GetDBConnexion()
    apprecs = sco_etud.appreciations_list(
        cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
    )
    for appr in apprecs:
        x_appr = Element(
            "appreciation",
            date=ndb.DateDMYtoISO(appr["date"]),
        )
        x_appr.text = scu.quote_xml_attr(appr["comment"])
        doc.append(x_appr)

    if is_appending:
        return None
    else:
        return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING)