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

"""Jury BUT: table synthèse résultats semestre / PV
"""
from flask import g, request, url_for

from openpyxl.styles import Alignment

from app import log
from app.but import cursus_but, jury_but
from app.models.but_validations import ValidationDUT120
from app.models.etudiants import Identite
from app.models.formsemestre import FormSemestre
from app.scodoc.gen_tables import GenTable
from app.scodoc import sco_excel
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_preferences
from app.scodoc import sco_utils as scu


def _descr_cursus_but(etud: Identite) -> str:
    "description de la liste des semestres BUT suivis"
    # prend simplement tous les semestre de type APC, ce qui sera faux si
    # l'étudiant change de spécialité au sein du même département
    # (ce qui ne peut normalement pas se produire)
    inscriptions = sorted(
        [
            ins
            for ins in etud.formsemestre_inscriptions
            if ins.formsemestre.formation.is_apc()
        ],
        key=lambda i: i.formsemestre.date_debut,
    )
    indices = [
        ins.formsemestre.semestre_id if ins.formsemestre.semestre_id is not None else -1
        for ins in inscriptions
    ]

    return ", ".join(f"S{indice}" for indice in indices)


def pvjury_page_but(formsemestre_id: int, fmt="html"):
    """Page récapitulant les décisions de jury BUT
    formsemestre peut être pair ou impair
    """
    formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
    assert formsemestre.formation.is_apc()
    title = "Procès-verbal de jury BUT"
    if fmt == "html":
        line_sep = "<br>"
    else:
        line_sep = "\n"
    rows, titles = pvjury_table_but(formsemestre, line_sep=line_sep)
    if fmt.startswith("xls"):
        titles.update(
            {
                "etudid": "etudid",
                "code_nip": "nip",
                "code_ine": "ine",
                "ects_but": "Total ECTS BUT",
                "civilite": "Civ.",
                "nom": "Nom",
                "prenom": "Prénom",
            }
        )
    # Style excel... passages à la ligne sur \n
    xls_style_base = sco_excel.excel_make_style()
    xls_style_base["alignment"] = Alignment(wrapText=True, vertical="top")
    tab = GenTable(
        base_url=f"{request.base_url}?formsemestre_id={formsemestre_id}",
        caption=title,
        columns_ids=titles.keys(),
        html_caption=title,
        html_class="pvjury_table_but table_leftalign",
        html_title=f"""<div style="margin-bottom: 8px;"><span
            style="font-size: 120%; font-weight: bold;">{title}</span>
        <span style="padding-left: 20px;">
        <a href="{url_for("notes.pvjury_page_but",
        scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, fmt="xlsx")}"
         class="stdlink">version excel</a></span></div>

        """,
        html_with_td_classes=True,
        origin=f"Généré par {scu.sco_version.SCONAME} le {scu.timedate_human_repr()}",
        page_title=title,
        pdf_title=title,
        preferences=sco_preferences.SemPreferences(),
        rows=rows,
        table_id="formation_table_recap",
        titles=titles,
        xls_columns_width={
            "nom": 32,
            "cursus": 12,
            "ues": 32,
            "niveaux": 32,
            "decision_but": 14,
            "diplome": 17,
            "devenir": 8,
            "observations": 12,
        },
        xls_style_base=xls_style_base,
    )
    return tab.make_page(fmt=fmt)


def pvjury_table_but(
    formsemestre: FormSemestre,
    etudids: list[int] = None,
    line_sep: str = "\n",
    only_diplome=False,
    anonymous=False,
    with_paragraph_nom=False,
) -> tuple[list[dict], dict]:
    """Table avec résultats jury BUT pour PV.
    Si etudids est None, prend tous les étudiants inscrits.
    """
    # remplace pour le BUT la fonction sco_pv_forms.pvjury_table
    annee_but = (formsemestre.semestre_id + 1) // 2
    referentiel_competence_id = formsemestre.formation.referentiel_competence_id
    if referentiel_competence_id is None:
        raise ScoValueError(
            "pas de référentiel de compétences associé à la formation de ce semestre !"
        )
    titles = {
        "nom_pv": "Code" if anonymous else "Nom",
        "cursus": "Cursus",
        "ects": "ECTS",
        "ues": "UE validées",
        "niveaux": "Niveaux de compétences validés",
        "decision_but": f"Décision BUT{annee_but}",
        "diplome": "Résultat au diplôme",
        "devenir": "Devenir",
        "observations": "Observations",
    }
    rows = []
    formsemestre_etudids = formsemestre.etuds_inscriptions.keys()
    if etudids is None:
        etudids = formsemestre_etudids
    for etudid in etudids:
        if not etudid in formsemestre_etudids:
            continue  # garde fou
        etud = Identite.get_etud(etudid)
        try:
            deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
            if deca.annee_but != annee_but:  # wtf ?
                log(
                    f"pvjury_table_but: inconsistent annee_but {deca.annee_but} != {annee_but}"
                )
                continue
        except ScoValueError:
            deca = None

        parcour = cursus_but.get_etud_parcours(
            etud, formsemestre.formation.referentiel_competence_id
        )
        ects_but_valides = (
            cursus_but.but_ects_valides(etud, parcour_id=parcour.id)
            if parcour
            else cursus_but.but_ects_valides(etud, referentiel_competence_id)
        )
        has_diplome = deca.valide_diplome() if deca else False
        diplome_lst = ["ADM"] if has_diplome else []
        validation_dut120 = ValidationDUT120.query.filter_by(
            etudid=etudid, formsemestre_id=formsemestre.id
        ).first()
        if validation_dut120:
            diplome_lst.append("Diplôme de DUT validé.")
        diplome_str = ". ".join(diplome_lst)
        row = {
            "nom_pv": (
                etud.code_ine or etud.code_nip or etud.id
                if anonymous  # Mode anonyme: affiche INE ou sinon NIP, ou id
                else etud.etat_civil_pv(
                    line_sep=line_sep, with_paragraph=with_paragraph_nom
                )
            ),
            "_nom_pv_order": etud.sort_key,
            "_nom_pv_target_attrs": f'class="etudinfo" id="{etud.id}"',
            "_nom_pv_td_attrs": f'id="{etud.id}" class="etudinfo"',
            "_nom_pv_target": url_for(
                "scolar.fiche_etud",
                scodoc_dept=g.scodoc_dept,
                etudid=etud.id,
            ),
            "cursus": _descr_cursus_but(etud),
            "ects": (
                f"""{deca.ects_annee():g}<br><br>Tot. {ects_but_valides:g}"""
                if deca
                else ""
            ),
            "_ects_xls": deca.ects_annee() if deca else "",
            "ects_but": ects_but_valides,
            "ues": deca.descr_ues_validation(line_sep=line_sep) if deca else "-",
            "niveaux": (
                deca.descr_niveaux_validation(line_sep=line_sep) if deca else "-"
            ),
            "decision_but": (
                (
                    scu.ETATS_INSCRIPTION_SHORT.get(deca.inscription_etat)
                    if deca.inscription_etat != scu.INSCRIT
                    else deca.code_valide
                )
                if deca
                else ""
            ),
            "devenir": (
                "Diplôme obtenu"
                if has_diplome
                else (
                    ", ".join([f"S{i}" for i in deca.get_autorisations_passage()])
                    if deca
                    else ""
                )
            ),
            "diplome": diplome_str,
            # pour exports excel seulement:
            "civilite": etud.civilite_etat_civil_str,
            "nom": etud.nom,
            "prenom": etud.prenom_etat_civil or etud.prenom or "",
            "etudid": etud.id,
            "code_nip": etud.code_nip,
            "code_ine": etud.code_ine,
        }
        if (deca and deca.valide_diplome()) or not only_diplome:
            rows.append(row)

    rows.sort(key=lambda x: x["_nom_pv_order"])
    return rows, titles