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

"""Jury BUT: calcul des décisions de jury annuelles "automatiques"
"""
from flask import g, url_for

from app import db
from app.but import jury_but, jury_dut120
from app.models import Identite, FormSemestre, ScolarNews, ValidationDUT120
from app.scodoc import sco_cache
from app.scodoc.sco_exceptions import ScoValueError


def formsemestre_validation_auto_but(
    formsemestre: FormSemestre, only_adm: bool = True, dry_run=False, with_dut120=True
) -> tuple[int, list[jury_but.DecisionsProposeesAnnee]]:
    """Calcul automatique des décisions de jury sur une "année" BUT.

    - N'enregistre jamais de décisions de l'année scolaire précédente, même
    si on a des RCUE "à cheval".
    - Normalement, only_adm est True et on n'enregistre que les décisions validantes
    de droit: ADM ou CMP.
    En revanche, si only_adm est faux, on enregistre la première décision proposée par ScoDoc
    (mode à n'utiliser que pour les tests unitaires vérifiant la saisie des jurys)

    Enregistre aussi le DUT120.

    Returns:
    - En mode normal, (nombre d'étudiants pour lesquels on a enregistré au moins un code, []])
    - En mode dry_run, (0, list[DecisionsProposeesAnnee])
    """
    if not formsemestre.formation.is_apc():
        raise ScoValueError("fonction réservée aux formations BUT")
    nb_etud_modif = 0
    decas = []
    with sco_cache.DeferredSemCacheManager():
        for etudid in formsemestre.etuds_inscriptions:
            etud = Identite.get_etud(etudid)
            deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
            if not dry_run:
                modified = deca.record_all(only_validantes=only_adm)
                modified |= validation_dut120_auto(etud, formsemestre)
                if modified:
                    nb_etud_modif += 1
            else:
                decas.append(deca)

    db.session.commit()
    ScolarNews.add(
        typ=ScolarNews.NEWS_JURY,
        obj=formsemestre.id,
        text=f"""Calcul jury automatique du semestre {formsemestre.html_link_status()}""",
        url=url_for(
            "notes.formsemestre_status",
            scodoc_dept=g.scodoc_dept,
            formsemestre_id=formsemestre.id,
        ),
    )
    return nb_etud_modif, decas


def validation_dut120_auto(etud: Identite, formsemestre: FormSemestre) -> bool:
    """Si l'étudiant n'a pas déjà validé son DUT120 dans cette spécialité
    et qu'il satisfait les confitions, l'enregistre.
    Returns True si nouvelle décision enregistrée.
    """
    refcomp = formsemestre.formation.referentiel_competence
    if not refcomp:
        raise ScoValueError("formation non associée à un référentiel de compétences")
    validation = ValidationDUT120.query.filter_by(
        etudid=etud.id, referentiel_competence_id=refcomp.id
    ).first()
    if validation:
        return False  # déjà enregistré
    if jury_dut120.etud_valide_dut120(etud, refcomp.id):
        new_validation = ValidationDUT120(
            etudid=etud.id,
            referentiel_competence_id=refcomp.id,
            formsemestre_id=formsemestre.id,  # Replace with appropriate value
        )
        db.session.add(new_validation)
        db.session.commit()
        return True
    return False  # ne peut pas valider