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

"""Génération bulletin BUT HTML synthétique en une page

On génère du HTML à partir d'un template Jinja.

## Données

Ces données sont des objets passés au template.

- `etud: Identite` : l'étudiant
- `formsemestre: FormSemestre` : le formsemestre d'où est émis ce bulletin
- `bulletins_sem: BulletinBUT` les données bulletins pour tous les étudiants
- `bul: dict` : le bulletin (dict, même structure que le json publié)
- `cursus: EtudCursusBUT`: infos sur le cursus BUT (niveaux validés etc)
- `decision_ues: dict`: `{ acronyme_ue : { 'code' : 'ADM' }}` accès aux décisions
  de jury d'UE
- `ects_total` : nombre d'ECTS validées dans ce cursus
- `ue_validation_by_niveau : dict` : les validations d'UE de chaque niveau du cursus
"""
import datetime
import time

from flask import render_template
from flask import g

from app.but.bulletin_but import BulletinBUT
from app.but import bulletin_but_court_pdf, cursus_but, validations_view
from app.decorators import (
    scodoc,
    permission_required,
)
from app.models import FormSemestre, FormSemestreInscription, Identite
from app.scodoc.codes_cursus import UE_STANDARD
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
from app.scodoc.sco_logos import find_logo
from app.scodoc.sco_permissions import Permission
import app.scodoc.sco_utils as scu
from app.views import notes_bp as bp
from app.views import ScoData


@bp.route(
    "/bulletin_but/<int:formsemestre_id>/<int:etudid>", endpoint="bulletin_but_html"
)
@bp.route(
    "/bulletin_but/<int:formsemestre_id>/<int:etudid>/pdf",
    defaults={"fmt": "pdf"},
    endpoint="bulletin_but_pdf",
)
@scodoc
@permission_required(Permission.ScoView)
def bulletin_but(formsemestre_id: int, etudid: int = None, fmt="html"):
    """Page HTML affichant le bulletin BUT simplifié"""
    etud: Identite = Identite.query.get_or_404(etudid)
    formsemestre: FormSemestre = (
        FormSemestre.query.filter_by(id=formsemestre_id)
        .join(FormSemestreInscription)
        .filter_by(etudid=etudid)
        .first_or_404()
    )
    if not formsemestre.formation.is_apc():
        raise ScoValueError("formation non BUT")

    args = _build_bulletin_but_infos(etud, formsemestre, fmt=fmt)

    if fmt == "pdf":
        filename = scu.bul_filename(formsemestre, etud, prefix="bul-but")
        bul_pdf = bulletin_but_court_pdf.make_bulletin_but_court_pdf(args)
        return scu.sendPDFFile(bul_pdf, filename + ".pdf")

    return render_template(
        "but/bulletin_court_page.j2",
        datetime=datetime,
        sco=ScoData(formsemestre=formsemestre, etud=etud),
        time=time,
        version="butcourt",
        **args,
    )


def bulletin_but_court_pdf_frag(
    etud: Identite, formsemestre: FormSemestre, stand_alone=False
) -> bytes:
    """Le code PDF d'un bulletin BUT court, à intégrer dans un document
    (pour les classeurs de tous les bulletins)
    """
    args = _build_bulletin_but_infos(etud, formsemestre)
    return bulletin_but_court_pdf.make_bulletin_but_court_pdf(
        args, stand_alone=stand_alone
    )


def _build_bulletin_but_infos(
    etud: Identite, formsemestre: FormSemestre, fmt="pdf"
) -> dict:
    """Réuni toutes les information pour le contenu d'un bulletin BUT court.
    On indique le format ("html" ou "pdf") car il y a moins d'infos en HTML.
    """
    bulletins_sem = BulletinBUT(formsemestre)
    if fmt == "pdf":
        bul: dict = bulletins_sem.bulletin_etud_complet(etud)
    else:  # la même chose avec un peu moins d'infos
        bul: dict = bulletins_sem.bulletin_etud(etud, force_publishing=True)
    decision_ues = (
        {x["acronyme"]: x for x in bul["semestre"]["decision_ue"]}
        if "semestre" in bul and "decision_ue" in bul["semestre"]
        else {}
    )
    if "ues" not in bul:
        raise ScoValueError("Aucune UE à afficher")
    cursus = cursus_but.EtudCursusBUT(etud, formsemestre.formation)
    refcomp = formsemestre.formation.referentiel_competence
    if refcomp is None:
        raise ScoNoReferentielCompetences(formation=formsemestre.formation)
    ue_validation_by_niveau = validations_view.get_ue_validation_by_niveau(
        refcomp, etud
    )
    ects_total = sum((v.ects() for v in ue_validation_by_niveau.values()))

    logo = find_logo(logoname="header", dept_id=g.scodoc_dept_id)

    ue_acronyms = bul["ues"].keys()
    args = {
        "bul": bul,
        "cursus": cursus,
        "decision_ues": decision_ues,
        "ects_total": ects_total,
        "etud": etud,
        "formsemestre": formsemestre,
        "logo": logo,
        "prefs": bulletins_sem.prefs,
        "title": f"Bul. {etud.nom_disp()} BUT (court)",
        "ue_validation_by_niveau": ue_validation_by_niveau,
        "ues_acronyms": [
            ue.acronyme
            for ue in bulletins_sem.res.ues
            if ue.type == UE_STANDARD and ue.acronyme in ue_acronyms
        ],
    }
    return args
