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

"""Code expérimental: si deux référentiel sont presques identiques
 (mêmes compétences, niveaux, parcours)
 essaie de changer une formation de référentiel.
"""

from app import clear_scodoc_cache, db

from app.models import (
    ApcParcours,
    ApcReferentielCompetences,
    ApcValidationRCUE,
    Formation,
    FormSemestreInscription,
    UniteEns,
)
from app.scodoc.sco_exceptions import ScoValueError


def formation_change_referentiel(
    formation: Formation, new_ref: ApcReferentielCompetences
):
    """Try to change ref."""
    if not formation.referentiel_competence:
        raise ScoValueError("formation non associée à un référentiel")
    if not isinstance(new_ref, ApcReferentielCompetences):
        raise ScoValueError("nouveau référentiel invalide")

    r = formation.referentiel_competence.map_to_other_referentiel(new_ref)
    if isinstance(r, str):
        raise ScoValueError(f"référentiels incompatibles: {r}")
    parcours_map, competences_map, niveaux_map = r

    formation.referentiel_competence = new_ref
    db.session.add(formation)
    # UEs - Niveaux et UEs - parcours
    for ue in formation.ues:
        if ue.niveau_competence:
            ue.niveau_competence_id = niveaux_map[ue.niveau_competence_id]
            db.session.add(ue)
        if ue.parcours:
            new_list = [
                db.session.get(ApcParcours, parcours_map[p.id]) for p in ue.parcours
            ]
            ue.parcours.clear()
            ue.parcours.extend(new_list)
            db.session.add(ue)
    # Modules / parcours et app_critiques
    for module in formation.modules:
        if module.parcours:
            new_list = [
                db.session.get(ApcParcours, parcours_map[p.id]) for p in module.parcours
            ]
            module.parcours.clear()
            module.parcours.extend(new_list)
            db.session.add(module)
        if module.app_critiques:  # efface les apprentissages critiques
            module.app_critiques.clear()
            db.session.add(module)
    # ApcValidationRCUE
    for valid_rcue in ApcValidationRCUE.query.join(
        UniteEns, UniteEns.id == ApcValidationRCUE.ue1_id
    ).filter_by(formation_id=formation.id):
        if valid_rcue.parcour:
            valid_rcue.parcour_id = parcours_map[valid_rcue.parcour.id]
            db.session.add(valid_rcue)
    for valid_rcue in ApcValidationRCUE.query.join(
        UniteEns, UniteEns.id == ApcValidationRCUE.ue2_id
    ).filter_by(formation_id=formation.id):
        if valid_rcue.parcour:
            valid_rcue.parcour_id = parcours_map[valid_rcue.parcour.id]
            db.session.add(valid_rcue)
    # FormSemestre / parcours_formsemestre
    for formsemestre in formation.formsemestres:
        new_list = [
            db.session.get(ApcParcours, parcours_map[p.id])
            for p in formsemestre.parcours
        ]
        formsemestre.parcours.clear()
        formsemestre.parcours.extend(new_list)
        db.session.add(formsemestre)
        # FormSemestreInscription.parcour_id
        for inscr in FormSemestreInscription.query.filter_by(
            formsemestre_id=formsemestre.id
        ).filter(FormSemestreInscription.parcour_id != None):
            if inscr.parcour_id is not None:
                inscr.parcour_id = parcours_map[inscr.parcour_id]
    #
    db.session.commit()
    clear_scodoc_cache()