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

##############################################################################
#
# ScoDoc
#
# 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
#
##############################################################################

"""Page accueil département (liste des semestres, etc)
"""

from sqlalchemy import desc
from flask import g, url_for, render_template
from flask_login import current_user
from flask_sqlalchemy.query import Query

import app
from app import log
from app.models import FormSemestre, ScolarNews
import app.scodoc.sco_utils as scu
from app.scodoc.gen_tables import GenTable
from app.scodoc.sco_permissions import Permission
import app.scodoc.notesdb as ndb
from app.scodoc import sco_modalites
from app.scodoc import sco_preferences
from app.scodoc import sco_users
from app.views import ScoData


def index_html(showcodes=0, showsemtable=0, export_table_formsemestres=False):
    "Page accueil département (liste des semestres)"
    showcodes = int(showcodes)
    showsemtable = int(showsemtable) or export_table_formsemestres

    # Liste tous les formsemestres du dept, le plus récent d'abord
    current_formsemestres = (
        FormSemestre.query.filter_by(dept_id=g.scodoc_dept_id, etat=True)
        .filter(FormSemestre.modalite != "EXT")
        .order_by(desc(FormSemestre.date_debut))
    )
    locked_formsemestres = (
        FormSemestre.query.filter_by(dept_id=g.scodoc_dept_id, etat=False)
        .filter(FormSemestre.modalite != "EXT")
        .order_by(desc(FormSemestre.date_debut))
    )
    formsemestres = (
        FormSemestre.query.filter_by(dept_id=g.scodoc_dept_id)
        .filter(FormSemestre.modalite != "EXT")
        .order_by(desc(FormSemestre.date_debut))
    )
    if showsemtable:  # table de tous les formsemestres
        table = _sem_table_gt(
            formsemestres,
            showcodes=showcodes,
            fmt="xlsx" if export_table_formsemestres else "html",
        )
        if export_table_formsemestres:
            return table  # cas spécial: on renvoie juste cette table
        html_table_formsemestres = table.html()
    else:
        html_table_formsemestres = None

    return render_template(
        "scolar/index.j2",
        current_user=current_user,
        dept_name=sco_preferences.get_preference("DeptName"),
        formsemestres=formsemestres,
        html_current_formsemestres=_show_current_formsemestres(
            current_formsemestres, showcodes
        ),
        html_table_formsemestres=html_table_formsemestres,
        locked_formsemestres=locked_formsemestres,
        nb_locked=locked_formsemestres.count(),
        nb_user_accounts=sco_users.get_users_count(dept=g.scodoc_dept),
        page_title=f"ScoDoc {g.scodoc_dept}",
        Permission=Permission,
        scolar_news_summary=ScolarNews.scolar_news_summary_html(),
        showsemtable=showsemtable,
        sco=ScoData(),
    )


def _convert_formsemestres_to_dicts(
    formsemestres: Query, showcodes: bool, fmt: str = "html"
) -> list[dict]:
    """ """
    if fmt == "html":
        # icon images:
        groupicon = scu.icontag("groupicon_img", title="Inscrits", border="0")
        emptygroupicon = scu.icontag(
            "emptygroupicon_img", title="Pas d'inscrits", border="0"
        )
        lockicon = scu.icontag("lock32_img", title="verrouillé", border="0")
    else:
        groupicon = "X"
        emptygroupicon = ""
        lockicon = "X"
    # génère liste de dict
    sems = []
    for formsemestre in formsemestres:
        nb_inscrits = len(formsemestre.inscriptions)
        formation = formsemestre.formation
        sem = {
            "anneescolaire": formsemestre.annee_scolaire(),
            "anneescolaire_str": formsemestre.annee_scolaire_str(),
            "bul_hide_xml": formsemestre.bul_hide_xml,
            "dateord": formsemestre.date_debut,
            "elt_annee_apo": formsemestre.elt_annee_apo,
            "elt_sem_apo": formsemestre.elt_sem_apo,
            "etapes_apo_str": formsemestre.etapes_apo_str(),
            "formation": f"{formation.acronyme} v{formation.version}",
            "_formation_target": url_for(
                "notes.ue_table",
                scodoc_dept=g.scodoc_dept,
                formation_id=formation.id,
                semestre_idx=formsemestre.semestre_id,
            ),
            "formsemestre_id": formsemestre.id,
            "groupicon": groupicon if nb_inscrits > 0 else emptygroupicon,
            "lockimg": lockicon,
            "modalite": formsemestre.modalite,
            "mois_debut": formsemestre.mois_debut(),
            "mois_fin": formsemestre.mois_fin(),
            "nb_inscrits": nb_inscrits,
            "responsable_name": formsemestre.responsables_str(),
            "semestre_id": formsemestre.semestre_id,
            "session_id": formsemestre.session_id(),
            "titre_num": formsemestre.titre_num(),
            "tmpcode": (f"<td><tt>{formsemestre.id}</tt></td>" if showcodes else ""),
        }
        sems.append(sem)
    return sems


def _show_current_formsemestres(formsemestres: Query, showcodes: bool) -> str:
    """html div avec les formsemestres courants de la page d'accueil"""

    H = []
    if formsemestres.count():
        H.append("""<div class="scobox-title">Sessions en cours</div>""")
        H.append(_sem_table(_convert_formsemestres_to_dicts(formsemestres, showcodes)))
    else:
        # aucun semestre courant: affiche aide
        H.append(
            """
        <div class="scobox-title">Aucune session en cours !</div>
        <p>Pour ajouter une session, aller dans <a href="Notes" id="link-programmes">Formations</a>,
        choisissez une formation, puis suivez le lien "<em>UE, modules, semestres</em>".
        </p>
        <p>Là, en bas de page, suivez le lien
        "<em>Mettre en place un nouveau semestre de formation...</em>"
        </p>"""
        )
    return "\n".join(H)


def _sem_table(sems: list[dict]) -> str:
    """Affiche liste des semestres, utilisée pour semestres en cours"""
    tmpl = f"""<tr class="%(trclass)s">%(tmpcode)s
    <td class="semicon">%(lockimg)s <a href="{
        url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept)}?formsemestre_id=%(formsemestre_id)s#groupes">%(groupicon)s</a></td>
    <td class="datesem">%(mois_debut)s <a title="%(session_id)s">-</a> %(mois_fin)s</td>
    <td class="titresem"><a class="stdlink" href="{url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept)}?formsemestre_id=%(formsemestre_id)s">%(titre_num)s</a>
    <span class="respsem">(%(responsable_name)s)</span>
    </td>
    </tr>
    """

    # Liste des semestres, groupés par modalités
    sems_by_mod, modalites = sco_modalites.group_sems_by_modalite(sems)

    H = ['<table class="listesems">']
    for modalite in modalites:
        if len(modalites) > 1:
            H.append('<tr><th colspan="3">%s</th></tr>' % modalite["titre"])

        if sems_by_mod[modalite["modalite"]]:
            cur_idx = sems_by_mod[modalite["modalite"]][0]["semestre_id"]
            for sem in sems_by_mod[modalite["modalite"]]:
                if cur_idx != sem["semestre_id"]:
                    sem["trclass"] = "firstsem"  # separe les groupes de semestres
                    cur_idx = sem["semestre_id"]
                else:
                    sem["trclass"] = ""
                H.append(tmpl % sem)
    H.append("</table>")
    return "\n".join(H)


def _sem_table_gt(formsemestres: Query, showcodes=False, fmt="html") -> GenTable:
    """Table des semestres
    Utilise une datatables.
    """
    sems = _style_sems(
        _convert_formsemestres_to_dicts(formsemestres, showcodes, fmt=fmt), fmt=fmt
    )
    sems.sort(
        key=lambda s: (
            -s["anneescolaire"],
            s["semestre_id"] if s["semestre_id"] > 0 else -s["semestre_id"] * 1000,
            s["modalite"],
        )
    )
    columns_ids = (
        "lockimg",
        "published",
        "dash_mois_fin",
        "semestre_id_n",
        "modalite",
        "titre_resp",
        "nb_inscrits",
        "formation",
        "etapes_apo_str",
        "elt_annee_apo",
        "elt_sem_apo",
    )
    if showcodes:
        columns_ids = ("formsemestre_id",) + columns_ids

    html_class = "stripe cell-border compact hover order-column table_leftalign semlist"
    if current_user.has_permission(Permission.EditApogee):
        html_class += " apo_editable"
    tab = GenTable(
        titles={
            "formsemestre_id": "id",
            "semestre_id_n": "S#",
            "modalite": "" if fmt == "html" else "Modalité",
            "mois_debut": "Début",
            "dash_mois_fin": "Année",
            "titre_resp": "Semestre",
            "nb_inscrits": "N",
            "etapes_apo_str": "Étape Apo.",
            "elt_annee_apo": "Elt. année Apo.",
            "elt_sem_apo": "Elt. sem. Apo.",
            "formation": "Formation",
        },
        columns_ids=columns_ids,
        rows=sems,
        table_id="semlist",
        html_class_ignore_default=True,
        html_class=html_class,
        html_sortable=True,
        html_table_attrs=f"""
            data-apo_save_url="{url_for('notes.formsemestre_set_apo_etapes', scodoc_dept=g.scodoc_dept)}"
            data-elt_annee_apo_save_url="{url_for('notes.formsemestre_set_elt_annee_apo', scodoc_dept=g.scodoc_dept)}"
            data-elt_sem_apo_save_url="{url_for('notes.formsemestre_set_elt_sem_apo', scodoc_dept=g.scodoc_dept)}"
        """,
        html_with_td_classes=True,
        preferences=sco_preferences.SemPreferences(),
    )

    return tab


def _style_sems(sems: list[dict], fmt="html") -> list[dict]:
    """ajoute quelques attributs de présentation pour la table"""
    is_h = fmt == "html"
    if is_h:
        icon_published = scu.ICON_PUBLISHED
        icon_hidden = scu.ICON_HIDDEN
    else:
        icon_published = "publié"
        icon_hidden = "non publié"
    for sem in sems:
        status_url = url_for(
            "notes.formsemestre_status",
            scodoc_dept=g.scodoc_dept,
            formsemestre_id=sem["formsemestre_id"],
        )
        sem["_groupicon_target"] = status_url
        sem["_formsemestre_id_class"] = "blacktt"
        sem["dash_mois_fin"] = (
            (f"""<a title="{sem['session_id']}">{sem['anneescolaire_str']}</a>""")
            if is_h
            else sem["anneescolaire_str"]
        )
        sem["_dash_mois_fin_class"] = "datesem"
        sem["titre_resp"] = (
            (
                f"""<a class="stdlink" href="{status_url}">{sem['titre_num']}</a>
                    <span class="respsem">({sem['responsable_name']})</span>"""
            )
            if is_h
            else f"""{sem['titre_num']} ({sem["responsable_name"]})"""
        )
        sem["published"] = icon_hidden if sem["bul_hide_xml"] else icon_published

        sem["_css_row_class"] = "css_S%d css_M%s" % (
            sem["semestre_id"],
            sem["modalite"],
        )
        sem["_semestre_id_class"] = "semestre_id"
        sem["_modalite_class"] = "modalite"
        if sem["semestre_id"] == -1:
            sem["semestre_id_n"] = ""
        else:
            sem["semestre_id_n"] = sem["semestre_id"]
        # pour édition codes Apogée:
        sem["_etapes_apo_str_td_attrs"] = (
            f""" data-oid="{sem['formsemestre_id']}" data-value="{sem['etapes_apo_str']}" """
        )
        sem["_elt_annee_apo_td_attrs"] = (
            f""" data-oid="{sem['formsemestre_id']}" data-value="{sem['elt_annee_apo']}" """
        )
        sem["_elt_sem_apo_td_attrs"] = (
            f""" data-oid="{sem['formsemestre_id']}" data-value="{sem['elt_sem_apo']}" """
        )
    return sems


def delete_dept(dept_id: int) -> str:
    """Suppression irréversible d'un département et de tous les objets rattachés"""
    assert isinstance(dept_id, int)

    # Un peu complexe, merci JMP :)
    cnx = ndb.GetDBConnexion()
    cursor = cnx.cursor()
    try:
        # 1- Create temp tables to store ids
        reqs = [
            "create temp table etudids_temp as select id from identite where dept_id = %(dept_id)s",
            """create temp table formsemestres_temp as select id
                from notes_formsemestre where dept_id = %(dept_id)s""",
            """create temp table moduleimpls_temp as select id from notes_moduleimpl
                where formsemestre_id in (select id from formsemestres_temp)""",
            """create temp table formations_temp as
                select id from notes_formations where dept_id = %(dept_id)s""",
            "create temp table tags_temp as select id from notes_tags where dept_id = %(dept_id)s",
        ]
        for r in reqs:
            log(f"delete_dept: {r}")
            cursor.execute(r, {"dept_id": dept_id})

        # 2- Delete student-related informations
        # ordered list of tables
        etud_tables = [
            "notes_notes",
            "group_membership",
            "billet_absence",
            "adresse",
            "absences",
            "notes_notes_log",
            "notes_moduleimpl_inscription",
            "itemsuivi",
            "notes_appreciations",
            "scolar_autorisation_inscription",
            "absences_notifications",
            "notes_formsemestre_inscription",
            "scolar_formsemestre_validation",
            "scolar_events",
        ]
        for table in etud_tables:
            log(f"delete from {table}")
            cursor.execute(
                f"delete from {table} where etudid in (select id from etudids_temp)"
            )

        reqs = [
            """delete from apc_validation_annee where referentiel_competence_id
                in (select id from apc_referentiel_competences where dept_id = %(dept_id)s)""",
            "delete from apc_referentiel_competences where dept_id = %(dept_id)s",
            "delete from sco_prefs where dept_id = %(dept_id)s",
            """delete from notes_semset_formsemestre
            where formsemestre_id in (select id from formsemestres_temp)""",
            """delete from notes_evaluation
            where moduleimpl_id in (select id from moduleimpls_temp)""",
            """delete from notes_modules_enseignants
            where moduleimpl_id in (select id from moduleimpls_temp)""",
            """delete from notes_formsemestre_uecoef
            where formsemestre_id in (select id from formsemestres_temp)""",
            """delete from notes_formsemestre_ue_computation_expr
            where formsemestre_id in (select id from formsemestres_temp)""",
            """delete from notes_formsemestre_responsables
            where formsemestre_id in (select id from formsemestres_temp)""",
            """delete from notes_moduleimpl
            where formsemestre_id in (select id from formsemestres_temp)""",
            """delete from notes_modules_tags
            where tag_id in (select id from tags_temp)""",
            "delete from notes_tags where dept_id = %(dept_id)s",
            "delete from notes_modules where formation_id in (select id from formations_temp)",
            """delete from notes_matieres
            where ue_id in (select id from notes_ue
                where formation_id in (select id from formations_temp))""",
            """delete from notes_formsemestre_etapes
            where formsemestre_id in (select id from formsemestres_temp)""",
            """delete from group_descr where partition_id in
            (select id from partition
                where formsemestre_id in (select id from formsemestres_temp))""",
            "delete from partition where formsemestre_id in (select id from formsemestres_temp)",
            """delete from notes_formsemestre_custommenu
                where formsemestre_id in (select id from formsemestres_temp)""",
            "delete from notes_ue where formation_id in (select id from formations_temp)",
            "delete from notes_formsemestre where dept_id = %(dept_id)s",
            "delete from scolar_news where dept_id = %(dept_id)s",
            "delete from notes_semset where dept_id = %(dept_id)s",
            "delete from notes_formations where dept_id = %(dept_id)s",
            "delete from itemsuivi_tags where dept_id = %(dept_id)s",
            "delete from identite where dept_id = %(dept_id)s",
            "delete from departement where id = %(dept_id)s",
            "drop table tags_temp",
            "drop table formations_temp",
            "drop table moduleimpls_temp",
            "drop table etudids_temp",
            "drop table formsemestres_temp",
        ]
        for r in reqs:
            log(f"delete_dept: {r}")
            cursor.execute(r, {"dept_id": dept_id})
    except Exception as e:
        cnx.rollback()
        return str(e)
    finally:
        cnx.commit()
        app.clear_scodoc_cache()
    return ""
