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

"""ScoDoc : gestion des fichiers archivés associés au formsemestre (PV de jury, ...)
"""
import json

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

from app import ScoDocJSONEncoder
from app.but import jury_but_pv
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre
from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc.sco_exceptions import ScoPermissionDenied
from app.scodoc import html_sco_header
from app.scodoc import sco_bulletins_pdf
from app.scodoc import sco_groups
from app.scodoc import sco_groups_view
from app.scodoc import sco_pv_forms
from app.scodoc import sco_pv_lettres_inviduelles
from app.scodoc import sco_pv_pdf

from app.scodoc.sco_archives import BaseArchiver
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_recapcomplet import (
    gen_formsemestre_recapcomplet_excel,
    gen_formsemestre_recapcomplet_html_table,
    gen_formsemestre_recapcomplet_json,
)
import app.scodoc.sco_utils as scu


class SemsArchiver(BaseArchiver):
    "Archiveur pour les PV de semestre"

    def __init__(self):
        BaseArchiver.__init__(self, archive_type="")


PV_ARCHIVER = SemsArchiver()


# ----------------------------------------------------------------------------


def do_formsemestre_archive(
    formsemestre: FormSemestre,
    group_ids: list[int] = None,  # si indiqué, ne prend que ces groupes
    description="",
    date_jury="",
    signature=None,  # pour lettres indiv
    date_commission=None,
    numero_arrete=None,
    code_vdi=None,
    show_title=False,
    pv_title=None,
    pv_title_session=None,
    with_paragraph_nom=False,
    anonymous=False,
    bul_version="long",
):
    """Make and store new archive for this formsemestre.
    Store:
    - tableau recap (xls), pv jury (xls et pdf), bulletins (xml et pdf), lettres individuelles (pdf)
    """

    if bul_version not in scu.BULLETINS_VERSIONS:
        raise ScoValueError(
            "do_formsemestre_archive: version de bulletin demandée invalide"
        )
    res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
    sem_archive_id = formsemestre.id
    archive_id = PV_ARCHIVER.create_obj_archive(
        sem_archive_id, description, formsemestre.dept_id
    )
    date = PV_ARCHIVER.get_archive_date(archive_id).strftime(scu.DATEATIME_FMT)

    if not group_ids:
        # tous les inscrits du semestre
        group_ids = [sco_groups.get_default_group(formsemestre.id)]
    groups_infos = sco_groups_view.DisplayedGroupsInfos(
        group_ids, formsemestre_id=formsemestre.id
    )
    groups_filename = "-" + groups_infos.groups_filename
    etudids = [m["etudid"] for m in groups_infos.members]

    # Tableau recap notes en XLS (pour tous les etudiants, n'utilise pas les groupes)
    data, _ = gen_formsemestre_recapcomplet_excel(res, include_evaluations=True)
    if data:
        PV_ARCHIVER.store(
            archive_id,
            "Tableau_moyennes" + scu.XLSX_SUFFIX,
            data,
            dept_id=formsemestre.dept_id,
        )
    # Tableau recap notes en HTML (pour tous les etudiants, n'utilise pas les groupes)
    table_html, _, _ = gen_formsemestre_recapcomplet_html_table(
        formsemestre, res, include_evaluations=True
    )
    if table_html:
        flash(f"Moyennes archivées le {date}", category="info")
        data = "\n".join(
            [
                html_sco_header.sco_header(
                    page_title=f"Moyennes archivées le {date}",
                    no_side_bar=True,
                ),
                f'<h2 class="fontorange">Valeurs archivées le {date}</h2>',
                """<style type="text/css">table.notes_recapcomplet tr {  color: rgb(185,70,0); }
                </style>""",
                table_html,
                html_sco_header.sco_footer(),
            ]
        )
        PV_ARCHIVER.store(
            archive_id, "Tableau_moyennes.html", data, dept_id=formsemestre.dept_id
        )

    # Bulletins en JSON
    data = gen_formsemestre_recapcomplet_json(formsemestre.id, xml_with_decisions=True)
    data_js = json.dumps(data, indent=1, cls=ScoDocJSONEncoder)
    if data:
        PV_ARCHIVER.store(
            archive_id,
            "Bulletins.json",
            data_js,
            dept_id=formsemestre.dept_id,
            compress=True,
        )
    # Décisions de jury, en XLS
    if formsemestre.formation.is_apc():
        response = jury_but_pv.pvjury_page_but(formsemestre.id, fmt="xls")
        data = response.get_data()
    else:  # formations classiques
        data = sco_pv_forms.formsemestre_pvjury(
            formsemestre.id, fmt="xls", publish=False
        )
    if data:
        PV_ARCHIVER.store(
            archive_id,
            "Decisions_Jury" + scu.XLSX_SUFFIX,
            data,
            dept_id=formsemestre.dept_id,
        )
    # Classeur bulletins (PDF)
    data, _ = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
        formsemestre.id, version=bul_version
    )
    if data:
        PV_ARCHIVER.store(
            archive_id,
            "Bulletins.pdf",
            data,
            dept_id=formsemestre.dept_id,
            compress=True,
        )
    # Lettres individuelles (PDF):
    data = sco_pv_lettres_inviduelles.pdf_lettres_individuelles(
        formsemestre.id,
        etudids=etudids,
        date_jury=date_jury,
        date_commission=date_commission,
        signature=signature,
    )
    if data:
        PV_ARCHIVER.store(
            archive_id,
            f"CourriersDecisions{groups_filename}.pdf",
            data,
            dept_id=formsemestre.dept_id,
        )

    # PV de jury (PDF):
    data = sco_pv_pdf.pvjury_pdf(
        formsemestre,
        etudids=etudids,
        date_commission=date_commission,
        date_jury=date_jury,
        numero_arrete=numero_arrete,
        code_vdi=code_vdi,
        show_title=show_title,
        pv_title_session=pv_title_session,
        pv_title=pv_title,
        with_paragraph_nom=with_paragraph_nom,
        anonymous=anonymous,
    )
    if data:
        PV_ARCHIVER.store(
            archive_id,
            f"PV_Jury{groups_filename}.pdf",
            data,
            dept_id=formsemestre.dept_id,
        )


def formsemestre_archive(formsemestre_id, group_ids: list[int] = None):
    """Make and store new archive for this formsemestre.
    (all students or only selected groups)
    """
    formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
    if not formsemestre.can_edit_pv():
        raise ScoPermissionDenied(
            dest_url=url_for(
                "notes.formsemestre_status",
                scodoc_dept=g.scodoc_dept,
                formsemestre_id=formsemestre_id,
            )
        )
    if not group_ids:
        # tous les inscrits du semestre
        group_ids = [sco_groups.get_default_group(formsemestre_id)]
    groups_infos = sco_groups_view.DisplayedGroupsInfos(
        group_ids, formsemestre_id=formsemestre_id
    )

    H = [
        html_sco_header.html_sem_header(
            "Archiver les PV et résultats du semestre",
            javascripts=sco_groups_view.JAVASCRIPTS,
            cssstyles=sco_groups_view.CSSSTYLES,
            init_qtip=True,
        ),
        """<p class="help">Cette page permet de générer et d'archiver tous
les documents résultant de ce semestre: PV de jury, lettres individuelles,
tableaux récapitulatifs.</p><p class="help">Les documents archivés sont
enregistrés et non modifiables, on peut les retrouver ultérieurement.
</p><p class="help">On peut archiver plusieurs versions des documents
(avant et après le jury par exemple).
</p>
        """,
    ]
    F = [
        f"""<p><em>Note: les documents sont aussi affectés par les réglages sur la page
        "<a class="stdlink" href="{
            url_for("scolar.edit_preferences", scodoc_dept=g.scodoc_dept)
        }">Paramétrage</a>"
        (accessible à l'administrateur du département).</em>
        </p>""",
        html_sco_header.sco_footer(),
    ]

    descr = [
        (
            "description",
            {"input_type": "textarea", "rows": 4, "cols": 77, "title": "Description"},
        ),
        ("sep", {"input_type": "separator", "title": "Informations sur PV de jury"}),
    ]
    descr += sco_pv_forms.descrform_pvjury(formsemestre)
    descr += [
        (
            "signature",
            {
                "input_type": "file",
                "size": 30,
                "explanation": "optionnel: image scannée de la signature pour les lettres individuelles",
            },
        ),
        (
            "bul_version",
            {
                "input_type": "menu",
                "title": "Version des bulletins archivés",
                "labels": [
                    "Version courte",
                    "Version intermédiaire",
                    "Version complète",
                ],
                "allowed_values": scu.BULLETINS_VERSIONS.keys(),
                "default": "long",
            },
        ),
    ]
    menu_choix_groupe = (
        """<div class="group_ids_sel_menu">Groupes d'étudiants à lister: """
        + sco_groups_view.menu_groups_choice(groups_infos)
        + """(pour les PV et lettres)</div>"""
    )

    tf = TrivialFormulator(
        request.base_url,
        scu.get_request_args(),
        descr,
        cancelbutton="Annuler",
        submitlabel="Générer et archiver les documents",
        name="tf",
        formid="group_selector",
        html_foot_markup=menu_choix_groupe,
    )
    if tf[0] == 0:
        return "\n".join(H) + "\n" + tf[1] + "\n".join(F)
    elif tf[0] == -1:
        msg = "Opération annulée"
    else:
        # submit
        sf = tf[2]["signature"]
        signature = sf.read()  # image of signature
        if tf[2]["anonymous"]:
            tf[2]["anonymous"] = True
        else:
            tf[2]["anonymous"] = False
        do_formsemestre_archive(
            formsemestre,
            group_ids=group_ids,
            description=tf[2]["description"],
            date_jury=tf[2]["date_jury"],
            date_commission=tf[2]["date_commission"],
            signature=signature,
            numero_arrete=tf[2]["numero_arrete"],
            code_vdi=tf[2]["code_vdi"],
            pv_title_session=tf[2]["pv_title_session"],
            pv_title=tf[2]["pv_title"],
            show_title=tf[2]["show_title"],
            with_paragraph_nom=tf[2]["with_paragraph_nom"],
            anonymous=tf[2]["anonymous"],
            bul_version=tf[2]["bul_version"],
        )
        msg = "Nouvelle archive créée"

    # submitted or cancelled:
    flash(msg)
    return flask.redirect(
        url_for(
            "notes.formsemestre_list_archives",
            scodoc_dept=g.scodoc_dept,
            formsemestre_id=formsemestre_id,
        )
    )


def formsemestre_list_archives(formsemestre_id):
    """Page listing archives"""
    formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
    sem_archive_id = formsemestre_id
    archives_descr = []
    for archive_id in PV_ARCHIVER.list_obj_archives(
        sem_archive_id, dept_id=formsemestre.dept_id
    ):
        a = {
            "archive_id": archive_id,
            "description": PV_ARCHIVER.get_archive_description(
                archive_id, dept_id=formsemestre.dept_id
            ),
            "date": PV_ARCHIVER.get_archive_date(archive_id),
            "content": PV_ARCHIVER.list_archive(
                archive_id, dept_id=formsemestre.dept_id
            ),
        }
        archives_descr.append(a)

    H = [html_sco_header.html_sem_header("Archive des PV et résultats ")]
    if not archives_descr:
        H.append("<p>aucune archive enregistrée</p>")
    else:
        H.append("<ul>")
        for a in archives_descr:
            archive_name = PV_ARCHIVER.get_archive_name(a["archive_id"])
            H.append(
                f"""<li>{a["date"].strftime("%d/%m/%Y %H:%M")} : <em>{a["description"]}</em>
                (<a href="{ url_for( "notes.formsemestre_delete_archive", scodoc_dept=g.scodoc_dept,
                    formsemestre_id=formsemestre_id, archive_name=archive_name
                )}">supprimer</a>)
                <ul>"""
            )
            for filename in a["content"]:
                H.append(
                    f"""<li><a href="{
                        url_for( "notes.formsemestre_get_archived_file", scodoc_dept=g.scodoc_dept,
                        formsemestre_id=formsemestre_id,
                        archive_name=archive_name,
                        filename=filename
                    )}">{filename[:-3] if filename.endswith(".gz") else filename}</a></li>"""
                )
            if not a["content"]:
                H.append("<li><em>aucun fichier !</em></li>")
            H.append("</ul></li>")
        H.append("</ul>")

    return "\n".join(H) + html_sco_header.sco_footer()


def formsemestre_get_archived_file(formsemestre_id, archive_name, filename):
    """Send file to client."""
    formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
    sem_archive_id = formsemestre.id
    return PV_ARCHIVER.get_archived_file(
        sem_archive_id, archive_name, filename, dept_id=formsemestre.dept_id
    )


def formsemestre_delete_archive(formsemestre_id, archive_name, dialog_confirmed=False):
    """Delete an archive"""
    formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
    if not formsemestre.can_edit_pv():
        raise ScoPermissionDenied(
            dest_url=url_for(
                "notes.formsemestre_status",
                scodoc_dept=g.scodoc_dept,
                formsemestre_id=formsemestre_id,
            )
        )
    sem_archive_id = formsemestre_id
    archive_id = PV_ARCHIVER.get_id_from_name(
        sem_archive_id, archive_name, dept_id=formsemestre.dept_id
    )

    dest_url = url_for(
        "notes.formsemestre_list_archives",
        scodoc_dept=g.scodoc_dept,
        formsemestre_id=formsemestre_id,
    )

    if not dialog_confirmed:
        return scu.confirm_dialog(
            f"""<h2>Confirmer la suppression de l'archive du {
                PV_ARCHIVER.get_archive_date(archive_id).strftime("%d/%m/%Y %H:%M")
            } ?</h2>
               <p>La suppression sera définitive.</p>
            """,
            dest_url="",
            cancel_url=dest_url,
            parameters={
                "formsemestre_id": formsemestre_id,
                "archive_name": archive_name,
            },
        )

    PV_ARCHIVER.delete_archive(archive_id, dept_id=formsemestre.dept_id)
    flash("Archive supprimée")
    return flask.redirect(dest_url)