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

"""Jury BUT: affichage/formulaire
"""

import re
import numpy as np

import flask
from flask import flash, render_template, url_for
from flask import g, request

from app import db
from app.but import jury_but
from app.but.jury_but import (
    DecisionsProposeesAnnee,
    DecisionsProposeesRCUE,
    DecisionsProposeesUE,
)
from app.models import (
    ApcNiveau,
    FormSemestre,
    FormSemestreInscription,
    Identite,
    UniteEns,
    ScolarAutorisationInscription,
    ScolarFormSemestreValidation,
    ScolarNews,
)
from app.scodoc import codes_cursus as sco_codes
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_utils as scu


def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
    """Affichage des décisions annuelles BUT
    Si pas read_only, menus sélection codes jury.
    """
    H = []

    if deca.jury_annuel:
        H.append(
            f"""
        <div class="but_section_annee">
            <div>
                <b>Décision de jury pour l'année :</b> {
                    _gen_but_select("code_annee", deca.codes, deca.code_valide,
                        disabled=True, klass="manual")
                }
                <span>({deca.code_valide or 'non'} enregistrée)</span>
            </div>
        </div>
        """
        )

    formsemestre_1 = deca.formsemestre_impair
    formsemestre_2 = deca.formsemestre_pair
    # Ordonne selon les dates des 2 semestres considérés (pour les redoublants à cheval):
    reverse_semestre = (
        deca.formsemestre_pair
        and deca.formsemestre_impair
        and deca.formsemestre_pair.date_debut < deca.formsemestre_impair.date_debut
    )
    if reverse_semestre:
        formsemestre_1, formsemestre_2 = formsemestre_2, formsemestre_1
    H.append(
        f"""
    <div class="titre_niveaux">
        <b>Niveaux de compétences et unités d'enseignement du BUT{deca.annee_but}</b>
        <a style="margin-left: 32px;" class="stdlink" target="_blank" rel="noopener noreferrer"
            href={
                url_for("notes.validation_rcues", scodoc_dept=g.scodoc_dept,
                    etudid=deca.etud.id,
                    formsemestre_id=formsemestre_2.id if formsemestre_2 else formsemestre_1.id
            )
        }>visualiser son cursus</a>
    </div>
    <div class="but_explanation">{deca.explanation}</div>
    <div class="but_annee">
    <div class="titre"></div>
    <div class="titre">{"S" +str(formsemestre_1.semestre_id)
        if formsemestre_1 else "-"}
        <span class="avertissement_redoublement">{formsemestre_1.annee_scolaire_str()
            if formsemestre_1 else ""}</span>
    </div>
    <div class="titre">{"S"+str(formsemestre_2.semestre_id)
        if formsemestre_2 else "-"}
        <span class="avertissement_redoublement">{formsemestre_2.annee_scolaire_str()
            if formsemestre_2 else ""}</span>
    </div>
    <div class="titre" title="Décisions sur RCUEs enregistrées sur l'ensemble du cursus">RCUE</div>
    """
    )
    for dec_rcue in deca.get_decisions_rcues_annee():
        rcue = dec_rcue.rcue
        niveau = rcue.niveau
        H.append(
            f"""<div class="but_niveau_titre">
            <div title="{niveau.competence.titre_long}">{niveau.competence.titre}</div>
            </div>"""
        )
        ue_impair, ue_pair = rcue.ue_1, rcue.ue_2
        # Les UEs à afficher : on regarde si read only et si dispense (non ré-inscription à l'UE)
        #  tuples (UniteEns, read_only, dispense)
        ues_ro_dispense = [
            (
                ue_impair,
                rcue.ue_cur_impair is None,
                deca.res_impair
                and ue_impair
                and (deca.etud.id, ue_impair.id) in deca.res_impair.dispense_ues,
            ),
            (
                ue_pair,
                rcue.ue_cur_pair is None,
                deca.res_pair
                and ue_pair
                and (deca.etud.id, ue_pair.id) in deca.res_pair.dispense_ues,
            ),
        ]
        # Ordonne selon les dates des 2 semestres considérés:
        if reverse_semestre:
            ues_ro_dispense[0], ues_ro_dispense[1] = (
                ues_ro_dispense[1],
                ues_ro_dispense[0],
            )
        # Colonnes d'UE:
        for ue, ue_read_only, ue_dispense in ues_ro_dispense:
            if ue:
                H.append(
                    _gen_but_niveau_ue(
                        ue,
                        deca.decisions_ues[ue.id],
                        disabled=read_only or ue_read_only,
                        annee_prec=ue_read_only,
                        niveau_id=ue.niveau_competence.id,
                        ue_dispense=ue_dispense,
                    )
                )
            else:
                H.append("""<div class="niveau_vide"></div>""")

        # Colonne RCUE
        H.append(_gen_but_rcue(dec_rcue, niveau))

    H.append("</div>")  # but_annee
    return "\n".join(H)


def _gen_but_select(
    name: str,
    codes: list[str],
    code_valide: str,
    disabled: bool = False,
    klass: str = "",
    data: dict = None,
    code_valide_label: str = "",
) -> str:
    "Le menu html select avec les codes"
    # if disabled:  # mauvaise idée car le disabled est traité en JS
    #    return f"""<div class="but_code {klass}">{code_valide}</div>"""
    data = data or {}
    options_htm = "\n".join(
        [
            f"""<option value="{code}"
            {'selected' if code == code_valide else ''}
            class="{'recorded' if code == code_valide else ''}"
            >{code
              if ((code != code_valide) or not code_valide_label)
              else code_valide_label
              }</option>"""
            for code in codes
        ]
    )
    return f"""<select required name="{name}"
        class="but_code {klass}"
        data-orig_code="{code_valide or (codes[0] if codes else '')}"
        data-orig_recorded="{code_valide or ''}"
        onchange="change_menu_code(this);"
        {"disabled" if disabled else ""}
        {" ".join( f'data-{k}="{v}"' for (k,v) in data.items() )}
        >{options_htm}</select>
        """


def _gen_but_niveau_ue(
    ue: UniteEns,
    dec_ue: DecisionsProposeesUE,
    disabled: bool = False,
    annee_prec: bool = False,
    niveau_id: int = None,
    ue_dispense: bool = False,
) -> str:
    if dec_ue.ue_status and dec_ue.ue_status["is_capitalized"]:
        moy_ue_str = f"""<span class="ue_cap">{
            scu.fmt_note(dec_ue.moy_ue_with_cap)}</span>"""

        if ue_dispense:
            etat_en_cours = """Non (ré)inscrit à cette UE"""
        else:
            etat_en_cours = f"""UE en cours
            {   "sans notes" if np.isnan(dec_ue.moy_ue)
                else
                ("avec moyenne <b>" + scu.fmt_note(dec_ue.moy_ue) + "</b>")
            }
            """

        scoplement = f"""<div class="scoplement">
            <div>
            <b>UE {ue.acronyme} capitalisée </b>
            <span>le {dec_ue.ue_status["event_date"].strftime(scu.DATE_FMT)}
            </span>
            </div>
            <div>
                { etat_en_cours }
            </div>
        </div>
        """
    elif dec_ue.formsemestre is None:
        # Validation d'UE antérieure (semestre hors année scolaire courante)
        if dec_ue.validation:
            moy_ue_str = f"""<span>{scu.fmt_note(dec_ue.validation.moy_ue)}</span>"""
            scoplement = f"""<div class="scoplement">
                <div>
                    <b>UE {ue.acronyme} antérieure </b>
                    <span>validée {dec_ue.validation.code}
                    le {dec_ue.validation.event_date.strftime(scu.DATE_FMT)}
                    </span>
                </div>
                <div>Non reprise dans l'année en cours</div>
            </div>
            """
        else:
            moy_ue_str = """<span>-</span>"""
            scoplement = """<div class="scoplement">
                <div>
                    <b>Pas d'UE en cours ou validée dans cette compétence de ce côté.</b>
                </div>
            </div>
            """
    else:
        moy_ue_str = f"""<span>{scu.fmt_note(dec_ue.moy_ue)}</span>"""
        if dec_ue.code_valide:
            date_str = (
                f"""enregistré le {dec_ue.validation.event_date.strftime(scu.DATEATIME_FMT)}"""
                if dec_ue.validation and dec_ue.validation.event_date
                else ""
            )
            scoplement = f"""<div class="scoplement">
            <div>Code {dec_ue.code_valide} {date_str}
            </div>
            </div>
            """
        else:
            if dec_ue.ue_status and dec_ue.ue_status["was_capitalized"]:
                scoplement = """<div class="scoplement">
                UE déjà capitalisée avec résultat moins favorable.
                </div>
                """
            else:
                scoplement = ""

    ue_class = ""  # 'recorded' if dec_ue.code_valide is not None else ''
    if dec_ue.code_valide is not None and dec_ue.codes:
        if dec_ue.code_valide == dec_ue.codes[0]:
            ue_class = "recorded"
        else:
            ue_class = "recorded_different"

    return f"""<div class="but_niveau_ue {ue_class}
        {'annee_prec' if annee_prec else ''}
        ">
    <div title="{ue.titre or ''}">{ue.acronyme}</div>
    <div class="but_note with_scoplement">
        <div>{moy_ue_str}</div>
        {scoplement}
    </div>
    <div class="but_code">{
        _gen_but_select("code_ue_"+str(ue.id),
            dec_ue.codes,
            dec_ue.code_valide,
            disabled=disabled,
            klass=f"code_ue ue_rcue_{niveau_id}" if not disabled else ""
        )
    }</div>

    </div>"""


def _gen_but_rcue(dec_rcue: DecisionsProposeesRCUE, niveau: ApcNiveau) -> str:
    if dec_rcue is None or not dec_rcue.rcue.complete:
        return """
        <div class="but_niveau_rcue niveau_vide with_scoplement">
                <div></div>
                <div class="scoplement">Pas de RCUE (UE non capitalisée ?)</div>
        </div>
        """

    code_propose_menu = dec_rcue.code_valide  # le code enregistré
    code_valide_label = code_propose_menu
    if dec_rcue.validation:
        if dec_rcue.code_valide == dec_rcue.codes[0]:
            descr_validation = dec_rcue.validation.html()
        else:  # on une validation enregistrée différence de celle proposée
            descr_validation = f"""Décision recommandée: <b>{dec_rcue.codes[0]}.</b>
                Il y avait {dec_rcue.validation.html()}"""
            if (
                sco_codes.BUT_CODES_ORDER[dec_rcue.codes[0]]
                > sco_codes.BUT_CODES_ORDER[dec_rcue.code_valide]
            ):
                code_propose_menu = dec_rcue.codes[0]
                code_valide_label = (
                    f"{dec_rcue.codes[0]} (actuel {dec_rcue.code_valide})"
                )
        scoplement = f"""<div class="scoplement">{descr_validation}</div>"""
    else:
        scoplement = ""  # "pas de validation"

    # Déjà enregistré ?
    niveau_rcue_class = ""
    if dec_rcue.code_valide is not None and dec_rcue.codes:
        if dec_rcue.code_valide == dec_rcue.codes[0]:
            niveau_rcue_class = "recorded"
        else:
            niveau_rcue_class = "recorded_different"

    return f"""
        <div class="but_niveau_rcue {niveau_rcue_class}
        ">
            <div class="but_note with_scoplement">
                <div>{scu.fmt_note(dec_rcue.rcue.moy_rcue)}</div>
                {scoplement}
            </div>
            <div class="but_code">
                {_gen_but_select("code_rcue_"+str(niveau.id),
                    dec_rcue.codes,
                    code_propose_menu,
                    disabled=True,
                    klass="manual code_rcue",
                    data = { "niveau_id" : str(niveau.id)},
                    code_valide_label = code_valide_label,
                )}
            </div>
        </div>
    """


# -------------
def infos_fiche_etud_html(etudid: int) -> str:
    """Section html pour fiche etudiant
    provisoire pour BUT 2022
    """
    etud = Identite.get_etud(etudid)
    inscriptions = (
        FormSemestreInscription.query.join(FormSemestreInscription.formsemestre)
        .filter(
            FormSemestreInscription.etudid == etud.id,
        )
        .order_by(FormSemestre.date_debut)
    )
    formsemestres_but = [
        i.formsemestre for i in inscriptions if i.formsemestre.formation.is_apc()
    ]
    if len(formsemestres_but) == 0:
        return ""

    # temporaire quick & dirty: affiche le dernier
    try:
        deca = DecisionsProposeesAnnee(etud, formsemestres_but[-1])
        return f"""<div class="infos_but">
            {show_etud(deca, read_only=True)}
            </div>
        """
    except ScoValueError:
        pass

    return ""