# -*- 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@gmail.com
#
##############################################################################

"""Generation bulletins de notes dans l'ancien format de ScoDoc (avant juillet 2011).

 Code partiellement redondant, copié de l'ancien système de gestion des bulletins.

 Voir sco_bulletins_standard pour une version plus récente.

 CE FORMAT N'EVOLUERA PLUS ET EST CONSIDERE COMME OBSOLETE.

"""

from flask import g, url_for

from reportlab.lib.colors import Color, blue
from reportlab.lib.units import cm, mm
from reportlab.platypus import Paragraph, Spacer, Table

from app.models import BulAppreciations
from app.scodoc import sco_bulletins_generator
from app.scodoc import sco_bulletins_pdf
from app.scodoc import sco_formsemestre
from app.scodoc.sco_permissions import Permission
from app.scodoc import sco_pdf
from app.scodoc.sco_pdf import SU
from app.scodoc import sco_preferences
import app.scodoc.sco_utils as scu


# Important: Le nom de la classe ne doit pas changer (bien le choisir), car il sera stocké en base de données (dans les préférences)
class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
    description = "Ancien format ScoDoc"  # la description doit être courte: elle apparait dans le menu de paramètrage ScoDoc
    supported_formats = ["html", "pdf"]

    def bul_title_pdf(self):
        """Génère la partie "titre" du bulletin de notes.
        Renvoie une liste d'objets platypus
        """
        objects = sco_bulletins_pdf.process_field(
            self.preferences["bul_pdf_title"], self.infos, self.style_field
        )
        objects.append(
            Spacer(1, 5 * mm)
        )  # impose un espace vertical entre le titre et la table qui suit
        return objects

    def bul_table(self, fmt="html"):
        """Table bulletin"""
        if fmt == "pdf":
            return self.bul_table_pdf()
        elif fmt == "html":
            return self.bul_table_html()
        else:
            raise ValueError(f"invalid bulletin format ({fmt})")

    def bul_table_pdf(self):
        """Génère la table centrale du bulletin de notes
        Renvoie une liste d'objets PLATYPUS (eg instance de Table).
        """
        P, pdfTableStyle, colWidths = _bulletin_pdf_table_legacy(
            self.infos, version=self.version
        )
        return [self.buildTableObject(P, pdfTableStyle, colWidths)]

    def bul_table_html(self):
        """Génère la table centrale du bulletin de notes: chaine HTML"""
        I = self.infos
        formsemestre_id = self.infos["formsemestre_id"]

        bul_show_abs_modules = sco_preferences.get_preference(
            "bul_show_abs_modules", formsemestre_id
        )

        sem = sco_formsemestre.get_formsemestre(formsemestre_id)
        if sem["bul_bgcolor"]:
            bgcolor = sem["bul_bgcolor"]
        else:
            bgcolor = "background-color: rgb(255,255,240)"

        linktmpl = '<span onclick="toggle_vis_ue(this);" class="toggle_ue">%s</span>'
        minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
        pluslink = linktmpl % scu.icontag("plus_img", border="0", alt="+")

        H = ['<table class="notes_bulletin" style="background-color: %s;">' % bgcolor]

        if sco_preferences.get_preference("bul_show_minmax", formsemestre_id):
            minmax = (
                '<span class="bul_minmax" title="[min, max] promo">[%s, %s]</span>'
                % (I["moy_min"], I["moy_max"])
            )
            bargraph = ""
        else:
            minmax = ""
            bargraph = I["moy_gen_bargraph_html"]
        # 1ere ligne: titres
        H.append(
            '<tr><td class="note_bold">Moyenne</td><td class="note_bold cell_graph">%s%s%s%s</td>'
            % (I["moy_gen"], I["etud_etat_html"], minmax, bargraph)
        )
        H.append('<td class="note_bold">%s</td>' % I["rang_txt"])
        H.append('<td class="note_bold">Note/20</td><td class="note_bold">Coef</td>')
        if bul_show_abs_modules:
            H.append('<td class="note_bold">Abs (J. / N.J.)</td>')
        H.append("</tr>")

        def list_modules(ue_modules, rowstyle):
            for mod in ue_modules:
                if mod["mod_moy_txt"] == "NI":
                    continue  # saute les modules où on n'est pas inscrit
                H.append('<tr class="notes_bulletin_row_mod%s">' % rowstyle)
                if sco_preferences.get_preference(
                    "bul_show_minmax_mod", formsemestre_id
                ):
                    rang_minmax = (
                        '%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>'
                        % (
                            mod["mod_rang_txt"],
                            scu.fmt_note(mod["stats"]["min"]),
                            scu.fmt_note(mod["stats"]["max"]),
                        )
                    )
                else:
                    rang_minmax = mod["mod_rang_txt"]  # vide si pas option rang
                H.append(
                    '<td>%s</td><td>%s</td><td>%s</td><td class="note">%s</td><td>%s</td>'
                    % (
                        mod["code_html"],
                        mod["name_html"],
                        rang_minmax,
                        mod["mod_moy_txt"],
                        mod["mod_coef_txt"],
                    )
                )
                if bul_show_abs_modules:
                    H.append("<td>%s</td>" % mod["mod_abs_txt"])
                H.append("</tr>")

                if self.version != "short":
                    # --- notes de chaque eval:
                    for e in mod["evaluations"]:
                        if e["visibulletin"] or self.version == "long":
                            H.append(
                                '<tr class="notes_bulletin_row_eval%s">' % rowstyle
                            )
                            H.append(
                                '<td>%s</td><td>%s</td><td class="bull_nom_eval">%s</td><td class="note">%s</td><td class="bull_coef_eval">%s</td></tr>'
                                % (
                                    "",
                                    "",
                                    e["name_html"],
                                    e["note_html"],
                                    e["coef_txt"],
                                )
                            )

        # Contenu table: UE après UE
        for ue in I["ues"]:
            ue_descr = ue["ue_descr_html"]
            coef_ue = ue["coef_ue_txt"]
            rowstyle = ""
            plusminus = minuslink  #
            if ue["ue_status"]["is_capitalized"]:
                if sco_preferences.get_preference(
                    "bul_show_ue_cap_details", formsemestre_id
                ):
                    plusminus = minuslink
                    hide = ""
                else:
                    plusminus = pluslink
                    hide = "sco_hide"
                H.append('<tr class="notes_bulletin_row_ue">')
                H.append(
                    '<td class="note_bold">%s%s</td><td class="note_bold">%s</td><td>%s</td><td>%s</td><td>%s</td>'
                    % (
                        plusminus,
                        ue["acronyme"],
                        ue["moy_ue_txt"],
                        ue_descr,
                        "",
                        coef_ue,
                    )
                )
                if bul_show_abs_modules:
                    H.append("<td></td>")
                H.append("</tr>")
                list_modules(ue["modules_capitalized"], " bul_row_ue_cap %s" % hide)

                coef_ue = ""
                ue_descr = "(en cours, non prise en compte)"
                rowstyle = (
                    " bul_row_ue_cur"  # style css pour indiquer UE non prise en compte
                )

            H.append('<tr class="notes_bulletin_row_ue">')
            if sco_preferences.get_preference("bul_show_minmax", formsemestre_id):
                moy_txt = (
                    '%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>'
                    % (
                        scu.fmt_note(ue["cur_moy_ue_txt"]),
                        scu.fmt_note(ue["min"]),
                        scu.fmt_note(ue["max"]),
                    )
                )
            else:
                moy_txt = ue["cur_moy_ue_txt"]

            H.append(
                '<td class="note_bold">%s%s</td><td class="note_bold">%s</td><td>%s</td><td>%s</td><td>%s</td>'
                % (minuslink, ue["acronyme"], moy_txt, ue_descr, "", coef_ue)
            )
            if bul_show_abs_modules:
                H.append("<td></td>")
            H.append("</tr>")
            list_modules(ue["modules"], rowstyle)

        H.append("</table>")

        # ---------------
        return "\n".join(H)

    def bul_part_below(self, fmt="html"):
        """Génère les informations placées sous la table de notes
        (absences, appréciations, décisions de jury...)
        """
        if fmt == "pdf":
            return self.bul_part_below_pdf()
        elif fmt == "html":
            return self.bul_part_below_html()
        else:
            raise ValueError(f"invalid bulletin format ({fmt})")

    def bul_part_below_pdf(self):
        """
        Renvoie une liste d'objets platypus
        """
        objects = []

        # ----- ABSENCES
        if self.preferences["bul_show_abs"]:
            objects.append(Spacer(1, 2 * mm))
            if self.infos["nbabs"]:
                metrique = scu.AssiduitesMetrics.short_to_str(
                    self.preferences["assi_metrique"], lower_plural=True
                )
                objects.append(
                    Paragraph(
                        SU(
                            f"""{self.infos['nbabs']:g} {metrique} d'absences, dont {
                                self.infos['nbabsjust']:g} justifiées."""
                        ),
                        self.CellStyle,
                    )
                )
            else:
                objects.append(
                    Paragraph(SU("Pas d'absences signalées."), self.CellStyle)
                )

        # ----- APPRECIATIONS
        appreciations = BulAppreciations.get_appreciations_list(
            self.formsemestre.id, self.etud.id
        )
        if appreciations:
            objects.append(Spacer(1, 3 * mm))
            objects.append(
                Paragraph(
                    SU(
                        "Appréciation : "
                        + "\n".join(BulAppreciations.summarize(appreciations))
                    ),
                    self.CellStyle,
                )
            )

        # ----- DECISION JURY
        if self.preferences["bul_show_decision"]:
            objects += sco_bulletins_pdf.process_field(
                self.preferences["bul_pdf_caption"],
                self.infos,
                self.style_field,
            )

        return objects

    def bul_part_below_html(self):
        """
        Renvoie chaine HTML
        """
        I = self.infos
        authuser = self.authuser
        H = []
        # --- Absences
        H.append(
            f"""<p>
        <a href="{ url_for('assiduites.calendrier_assi_etud',
                           scodoc_dept=g.scodoc_dept, etudid=I['etudid']) }" class="bull_link">
        <b>Absences :</b>{I['nbabs']} demi-journées, dont {I['nbabsjust']} justifiées
        (pendant ce semestre).
        </a></p>
            """
        )
        # --- Decision Jury
        if I["situation"]:
            H.append("""<p class="bull_situation">%(situation)s</p>""" % I)
        # --- Appreciations
        # le dir. des etud peut ajouter des appreciations,
        # mais aussi le chef (perm. EtudInscrit)
        can_edit_app = (authuser.id in self.infos["responsables"]) or (
            authuser.has_permission(Permission.EtudInscrit)
        )
        H.append('<div class="bull_appreciations">')
        appreciations = BulAppreciations.get_appreciations_list(
            self.formsemestre.id, self.etud.id
        )
        if appreciations:
            H.append("<p><b>Appréciations</b></p>")
        for appreciation in appreciations:
            if can_edit_app:
                mlink = f"""<a class="stdlink" href="{
                        url_for('notes.appreciation_add_form', scodoc_dept=g.scodoc_dept, appreciation_id=appreciation.id)
                    }">modifier</a>
                    <a class="stdlink" href="{
                        url_for('notes.appreciation_add_form', scodoc_dept=g.scodoc_dept, appreciation_id=appreciation.id, suppress=1)
                    }">supprimer</a>"""
            else:
                mlink = ""
            H.append(
                f"""<p>
                <span class="bull_appreciations_date">{
                    appreciation.date.strftime(scu.DATE_FMT) if appreciation.date else ""
                }</span>
                {appreciation.comment_safe()}
                <span class="bull_appreciations_link">{mlink}</span>
                </p>"""
            )
        if can_edit_app:
            H.append(
                f"""<p>
                <a class="stdlink" href="{
                    url_for('notes.appreciation_add_form',
                            scodoc_dept=g.scodoc_dept,
                            etudid=self.etud.id,
                            formsemestre_id=self.formsemestre.id)
                }">Ajouter une appréciation</a>
                </p>"""
            )
        H.append("</div>")
        # ---------------
        return "\n".join(H)

    def bul_signatures_pdf(self):
        """Génère les signatures placées en bas du bulletin
        Renvoie une liste d'objets platypus
        """
        show_left = self.preferences["bul_show_sig_left"]
        show_right = self.preferences["bul_show_sig_right"]
        if show_left or show_right:
            if show_left:
                L = [
                    [
                        sco_bulletins_pdf.process_field(
                            self.preferences["bul_pdf_sig_left"],
                            self.infos,
                            self.style_field,
                        )
                    ]
                ]
            else:
                L = [[""]]
            if show_right:
                L[0].append(
                    sco_bulletins_pdf.process_field(
                        self.preferences["bul_pdf_sig_right"],
                        self.infos,
                        self.style_field,
                    )
                )
            else:
                L[0].append("")
            t = Table(L)
            t._argW[0] = 10 * cm  # fixe largeur colonne gauche

            return [Spacer(1, 1.5 * cm), t]  # espace vertical avant signatures
        else:
            return []


# sco_bulletins_generator.register_bulletin_class(BulletinGeneratorLegacy)


class BulTableStyle(object):
    """Construction du style de tables reportlab platypus pour les bulletins "classiques" """

    LINEWIDTH = 0.5
    LINECOLOR = Color(0, 0, 0)
    UEBGCOLOR = Color(
        170 / 255.0, 187 / 255.0, 204 / 255.0
    )  # couleur fond lignes titres UE
    MODSEPCOLOR = Color(
        170 / 255.0, 170 / 255.0, 170 / 255.0
    )  # lignes séparant les modules

    def __init__(self):
        self.pdfTableStyle = [
            ("LINEBELOW", (0, 0), (-1, 0), self.LINEWIDTH, self.LINECOLOR)
        ]
        self.tabline = 0

    def get_style(self):
        "get resulting style (a list of platypus table commands)"
        # ajoute cadre extérieur bleu:
        self.pdfTableStyle.append(("BOX", (0, 0), (-1, -1), 0.4, blue))

        return self.pdfTableStyle

    def newline(self, ue_type=None):
        self.tabline += 1
        if ue_type == "cur":  # UE courante non prise en compte (car capitalisee)
            self.pdfTableStyle.append(
                (
                    "BACKGROUND",
                    (0, self.tabline),
                    (-1, self.tabline),
                    Color(210 / 255.0, 210 / 255.0, 210 / 255.0),
                )
            )

    def ueline(self):  # met la ligne courante du tableau pdf en style 'UE'
        self.newline()
        i = self.tabline
        self.pdfTableStyle.append(("BACKGROUND", (0, i), (-1, i), self.UEBGCOLOR))

    def modline(
        self, ue_type=None
    ):  # met la ligne courante du tableau pdf en style 'Module'
        self.newline(ue_type=ue_type)
        i = self.tabline
        self.pdfTableStyle.append(("LINEABOVE", (0, i), (-1, i), 1, self.MODSEPCOLOR))


def _bulletin_pdf_table_legacy(I, version="long"):
    """Génère la table centrale du bulletin de notes
    Renvoie un triplet:
    - table (liste de listes de chaines de caracteres)
    - style (commandes table Platypus)
    - largeurs de colonnes
    """
    S = BulTableStyle()
    P = []  # elems pour gen. pdf
    formsemestre_id = I["formsemestre_id"]
    bul_show_abs_modules = sco_preferences.get_preference(
        "bul_show_abs_modules", formsemestre_id
    )

    if sco_preferences.get_preference("bul_show_minmax", formsemestre_id):
        minmax = ' <font size="8">[%s, %s]</font>' % (I["moy_min"], I["moy_max"])
    else:
        minmax = ""

    t = [
        "Moyenne",
        "%s%s%s" % (I["moy_gen"], I["etud_etat_html"], minmax),
        I["rang_txt"],
        "Note/20",
        "Coef",
    ]
    if bul_show_abs_modules:
        t.append("Abs (J. / N.J.)")
    P.append(sco_pdf.bold_paras(t))

    def list_modules(ue_modules, ue_type=None):
        "ajoute les lignes decrivant les modules d'une UE, avec eventuellement les évaluations de chacun"
        for mod in ue_modules:
            if mod["mod_moy_txt"] == "NI":
                continue  # saute les modules où on n'est pas inscrit
            S.modline(ue_type=ue_type)
            if sco_preferences.get_preference("bul_show_minmax_mod", formsemestre_id):
                rang_minmax = '%s <font size="8">[%s, %s]</font>' % (
                    mod["mod_rang_txt"],
                    scu.fmt_note(mod["stats"]["min"]),
                    scu.fmt_note(mod["stats"]["max"]),
                )
            else:
                rang_minmax = mod["mod_rang_txt"]  # vide si pas option rang
            t = [
                mod["code"] or "",
                mod["name"] or "",
                rang_minmax,
                mod["mod_moy_txt"],
                mod["mod_coef_txt"],
            ]
            if bul_show_abs_modules:
                t.append(mod["mod_abs_txt"])
            P.append(t)
            if version != "short":
                # --- notes de chaque eval:
                for e in mod["evaluations"]:
                    if e["visibulletin"] or version == "long":
                        S.newline(ue_type=ue_type)
                        t = ["", "", e["name"], e["note_txt"], e["coef_txt"]]
                        if bul_show_abs_modules:
                            t.append("")
                        P.append(t)

    for ue in I["ues"]:
        ue_descr = ue["ue_descr_txt"]
        coef_ue = ue["coef_ue_txt"]
        ue_type = None
        if ue["ue_status"]["is_capitalized"]:
            t = [ue["acronyme"], ue["moy_ue_txt"], ue_descr, "", coef_ue]
            if bul_show_abs_modules:
                t.append("")
            P.append(sco_pdf.bold_paras(t))
            coef_ue = ""
            ue_descr = "(en cours, non prise en compte)"
            S.ueline()
            if sco_preferences.get_preference(
                "bul_show_ue_cap_details", formsemestre_id
            ):
                list_modules(ue["modules_capitalized"])
            ue_type = "cur"

        if sco_preferences.get_preference("bul_show_minmax", formsemestre_id):
            moy_txt = '%s <font size="8">[%s, %s]</font>' % (
                ue["cur_moy_ue_txt"],
                ue["min"],
                ue["max"],
            )
        else:
            moy_txt = ue["cur_moy_ue_txt"]
        t = [ue["acronyme"], moy_txt, ue_descr, "", coef_ue]
        if bul_show_abs_modules:
            t.append("")
        P.append(sco_pdf.bold_paras(t))
        S.ueline()
        list_modules(ue["modules"], ue_type=ue_type)

    # Largeur colonnes:
    colWidths = [None, 5 * cm, 6 * cm, 2 * cm, 1.2 * cm]
    if len(P[0]) > 5:
        colWidths.append(1.5 * cm)  # absences/modules

    return P, S.get_style(), colWidths