# -*- mode: 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
#
##############################################################################

"""Export d'une table avec les résultats de tous les étudiants
"""
from flask import url_for, g, request

from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
from app import log
from app.models import Formation
from app.scodoc import html_sco_header
from app.scodoc import sco_bac
from app.scodoc import codes_cursus
from app.scodoc import sco_preferences
from app.scodoc import sco_pv_dict
from app.scodoc import sco_etud
import sco_version
from app.scodoc.gen_tables import GenTable
from app.scodoc.codes_cursus import NO_SEMESTRE_ID


def _build_results_table(start_date=None, end_date=None, types_parcours=[]):
    """Construit une table avec les résultats de jury de TOUS les étudiants
    de TOUS les semestres ScoDoc de ce département entre les dates indiquées
    (c'est à dire commençant APRES ou à start_date et terminant avant ou à end_date)
    Les dates sont des chaines iso.
    """
    formsemestre_ids = get_set_formsemestre_id_dates(start_date, end_date)
    # Décisions de jury de tous les semestres:
    dpv_by_sem = {}
    for formsemestre_id in formsemestre_ids:
        dpv_by_sem[formsemestre_id] = sco_pv_dict.dict_pvjury(
            formsemestre_id, with_parcours_decisions=True
        )

    semlist = [dpv["formsemestre"] for dpv in dpv_by_sem.values() if dpv]
    semlist_parcours = []
    for sem in semlist:
        sem["formation"] = Formation.query.get_or_404(sem["formation_id"]).to_dict()
        sem["parcours"] = codes_cursus.get_cursus_from_code(
            sem["formation"]["type_parcours"]
        )
        if sem["parcours"].TYPE_CURSUS in types_parcours:
            semlist_parcours.append(sem)
    formsemestre_ids_parcours = [sem["formsemestre_id"] for sem in semlist_parcours]

    # Ensemble des étudiants
    etuds_infos = (
        {}
    )  # etudid : { formsemestre_id d'inscription le plus recent dans les dates considérées, etud }
    for formsemestre_id in formsemestre_ids_parcours:
        formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
        nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
        etudids = nt.get_etudids()
        for etudid in etudids:
            if etudid not in etuds_infos:  # pas encore traité ?
                etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
                for sem in etud["sems"]:  # le plus récent d'abord
                    if sem["formsemestre_id"] in formsemestre_ids_parcours:
                        etuds_infos[etudid] = {
                            "recent_formsemestre_id": sem["formsemestre_id"],
                            "etud": etud,
                        }
                        break
                # sanity check
                assert etudid in etuds_infos
    # Construit la table (semblable à pvjury_table)
    rows, titles, columns_ids = _build_results_list(dpv_by_sem, etuds_infos)
    tab = GenTable(
        rows=rows,
        titles=titles,
        columns_ids=columns_ids,
        filename=scu.make_filename("scodoc-results-%s-%s" % (start_date, end_date)),
        caption="Résultats ScoDoc de %s à %s" % (start_date, end_date),
        origin="Généré par %s le " % sco_version.SCONAME
        + scu.timedate_human_repr()
        + "",
        html_class="table_leftalign",
        html_sortable=True,
        preferences=sco_preferences.SemPreferences(),
        table_id="export_result_table",
    )
    return tab, semlist


def _build_results_list(dpv_by_sem, etuds_infos):
    """Construit la table (semblable à pvjury_table)
    Returns:
        rows, titles, columns_ids
    """
    titles = {
        "anneescolaire": "Année",
        "periode": "Période",
        "sid": "Semestre",
        "etudid": "etudid",
        "code_nip": "NIP",
        "nom": "Nom",
        "prenom": "Prénom",
        "civilite_str": "Civ.",
        "nom_usuel": "Nom usuel",
        "bac": "Bac",
        "parcours": "Parcours",
        "devenir": "Devenir",
    }
    columns_ids = [
        "anneescolaire",
        "periode",
        "sid",
        "code_nip",
        "civilite_str",
        "nom",
        # 'nom_usuel', # inutile ?
        "prenom",
        "bac",
        "parcours",
    ]

    # Recherche la liste des indices de semestres à considérer
    all_idx = set()
    for etudid in etuds_infos:
        # la décision de jury à considérer pour cet étudiant:
        e = dpv_by_sem[etuds_infos[etudid]["recent_formsemestre_id"]]["decisions_dict"][
            etudid
        ]
        all_idx |= set(e["parcours_decisions"].keys())
    sem_ids = sorted(all_idx)
    # ajoute les titres des colonnes résultats de semestres
    for i in sem_ids:
        if i != NO_SEMESTRE_ID:
            titles[i] = "S%d" % i
        else:
            titles[i] = "S"  # pas très parlant ?
        columns_ids += [i]
    columns_ids += ["devenir"]
    # Construit la liste:
    rows = []
    for etudid in etuds_infos:
        etud = etuds_infos[etudid]["etud"]
        bac = sco_bac.Baccalaureat(etud["bac"], etud["specialite"])
        dpv = dpv_by_sem[etuds_infos[etudid]["recent_formsemestre_id"]]
        dec = dpv["decisions_dict"][etudid]
        l = {
            "etudid": etudid,
            "code_nip": etud["code_nip"],
            "nom": etud["nom"],
            "nom_usuel": etud["nom_usuel"],
            "prenom": etud["prenom"],
            "civilite_str": etud["civilite_str"],
            "_nom_target": url_for(
                "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid
            ),
            "_nom_td_attrs": f'id="{etudid}" class="etudinfo"',
            "bac": bac.abbrev(),
            "parcours": dec["parcours"],
        }
        for sem in reversed(etud["sems"]):
            r = l.copy()
            dpv = dpv_by_sem.get(sem["formsemestre_id"], None)
            if dpv:  # semestre à inclure dans ce rapport
                dec = dpv["decisions_dict"].get(etudid, None)
                if dec and dec["decision_sem"]:
                    code = dec["decision_sem"]["code"]
                    if dec["validation_parcours"]:
                        r["devenir"] = "Diplôme obtenu"
                    else:
                        r["devenir"] = dec["autorisations_descr"]
                else:
                    code = "-"
                r[sem["semestre_id"]] = code
                r["periode"] = sem["periode"]
                r["anneescolaire"] = scu.annee_scolaire_debut(
                    int(sem["annee_debut"]), sem["mois_debut_ord"]
                )
                r["sid"] = "{} {} {}".format(
                    sem["sem_id_txt"], g.scodoc_dept, sem["modalite"]
                )
                rows.append(r)

    return rows, titles, columns_ids


def get_set_formsemestre_id_dates(start_date, end_date) -> set:
    """Ensemble des formsemestre_id entre ces dates"""
    s = ndb.SimpleDictFetch(
        """SELECT id
        FROM notes_formsemestre
        WHERE date_debut >= %(start_date)s
        AND date_fin <= %(end_date)s
        AND dept_id = %(dept_id)s
        """,
        {"start_date": start_date, "end_date": end_date, "dept_id": g.scodoc_dept_id},
    )
    return {x["id"] for x in s}


def scodoc_table_results(
    start_date="", end_date="", types_parcours: list = None, fmt="html"
):
    """Page affichant la table des résultats
    Les dates sont en dd/mm/yyyy (datepicker javascript)
    types_parcours est la liste des types de parcours à afficher
    (liste de chaines, eg ['100', '210'] )
    """
    log(f"scodoc_table_results: start_date={start_date!r}")
    if not types_parcours:
        types_parcours = []
    if not isinstance(types_parcours, list):
        types_parcours = [types_parcours]
    if start_date:
        start_date_iso = ndb.DateDMYtoISO(start_date)
    if end_date:
        end_date_iso = ndb.DateDMYtoISO(end_date)
    types_parcours = [int(x) for x in types_parcours if x]

    if start_date and end_date:
        tab, semlist = _build_results_table(
            start_date_iso, end_date_iso, types_parcours
        )
        tab.base_url = "%s?start_date=%s&end_date=%s&types_parcours=%s" % (
            request.base_url,
            start_date,
            end_date,
            "&types_parcours=".join([str(x) for x in types_parcours]),
        )
        if fmt != "html":
            return tab.make_page(fmt=fmt, with_html_headers=False)
        tab_html = tab.html()
        nb_rows = tab.get_nb_rows()
    else:
        tab = None
        nb_rows = 0
        tab_html = ""
        semlist = []

    # affiche la liste des semestres utilisés:
    info_sems = ["<ul>"]
    menu_options = []
    type_parcours_set = set()
    for sem in sorted(semlist, key=lambda x: x["dateord"]):
        if sem["parcours"].TYPE_CURSUS in types_parcours:
            selected = "selected"
        else:
            selected = ""
        if sem["parcours"].TYPE_CURSUS not in type_parcours_set:
            type_parcours_set.add(sem["parcours"].TYPE_CURSUS)
            menu_options.append(
                '<option value="%s" %s>%s</option>'
                % (sem["parcours"].TYPE_CURSUS, selected, sem["parcours"].__doc__)
            )

        if sem["parcours"].TYPE_CURSUS in types_parcours:
            info_sems.append(
                '<li><a class="stdlink" href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titremois)s</a></li>'
                % sem
            )

    info_sems.append("</ul>")

    H = [
        html_sco_header.sco_header(
            page_title="Export résultats",
            init_qtip=True,
            javascripts=html_sco_header.BOOTSTRAP_MULTISELECT_JS
            + ["js/etud_info.js", "js/export_results.js"],
            cssstyles=html_sco_header.BOOTSTRAP_MULTISELECT_CSS,
        ),
        # XXX
        """
        <h2>Table des résultats de tous les semestres</h2>
        <p class="warning">Développement en cours / attention !</p>
        """,
        _DATE_FORM.format(
            start_date=start_date,
            end_date=end_date,
            menu_options="\n".join(menu_options),
        ),
        """<div>
        <h4>%d étudiants dans les %d semestres de cette période</h4>
        </div>
        """
        % (nb_rows, len(semlist)),
        tab_html,
        """<div><h4>Semestres pris en compte:</h4>
        """,
        "\n".join(info_sems),
        """</div>""",
        html_sco_header.sco_footer(),
    ]
    return "\n".join(H)


# Formulaire pour saisie dates et sélection parcours
_DATE_FORM = """
<form method="get">
<div><b>Choisir les dates :</b>
<div>Début: <input type="text" name="start_date" size="10" value="{start_date}" class="datepicker"/> </div>
<div>Fin: <input type="text" name="end_date" size="10" value="{end_date}" class="datepicker"/></div>
<input type="submit" name="" value=" OK " width=100/>
</div>
<div>
<b>Types de parcours :</b>
<select name="types_parcours" id="parcours_sel" class="multiselect" multiple="multiple">
{menu_options}
</select>

<input type="submit" name="" value=" charger " width=100/>
</form>
"""

# ------- debug
"""
# /opt/scodoc/bin/zopectl debug
from debug import *
from app.scodoc.sco_export_results import *
_ = go_dept(app, 'RT').Notes
etudid = 'EID27764'
etud = sco_etud.get_etud_info( etudid=etudid, filled=True)[0]

start_date='2015-08-15'
end_date='2017-08-31'

formsemestre_ids = get_set_formsemestre_id_dates( start_date, end_date)
dpv_by_sem = {}
for formsemestre_id in formsemestre_ids:
    dpv_by_sem[formsemestre_id] = sco_pv_dict.dict_pvjury( formsemestre_id, with_parcours_decisions=True)

semlist = [ dpv['formsemestre'] for dpv in dpv_by_sem.values() ]

"""