"""ScoDoc 9 models : Unités d'Enseignement (UE)
"""

from app import db
from app.models import APO_CODE_STR_LEN
from app.models import SHORT_STR_LEN
from app.scodoc import sco_utils as scu


class UniteEns(db.Model):
    """Unité d'Enseignement (UE)"""

    __tablename__ = "notes_ue"

    id = db.Column(db.Integer, primary_key=True)
    ue_id = db.synonym("id")
    formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id"))
    acronyme = db.Column(db.Text(), nullable=False)
    numero = db.Column(db.Integer)  # ordre de présentation
    titre = db.Column(db.Text())
    # Le semestre_idx n'est pas un id mais le numéro du semestre: 1, 2, ...
    # En ScoDoc7 et pour les formations classiques, il est NULL
    # (le numéro du semestre étant alors déterminé par celui des modules de l'UE)
    # Pour les formations APC, il est obligatoire (de 1 à 6 pour le BUT):
    semestre_idx = db.Column(db.Integer, nullable=True, index=True)
    # Type d'UE: 0 normal ("fondamentale"), 1 "sport", 2 "projet et stage (LP)",
    # 4 "élective"
    type = db.Column(db.Integer, default=0, server_default="0")
    # Les UE sont "compatibles" (pour la capitalisation) ssi elles ont ^m code
    # note: la fonction SQL notes_newid_ucod doit être créée à part
    ue_code = db.Column(
        db.String(SHORT_STR_LEN),
        server_default=db.text("notes_newid_ucod()"),
        nullable=False,
    )
    ects = db.Column(db.Float)  # nombre de credits ECTS
    is_external = db.Column(db.Boolean(), default=False, server_default="false")
    # id de l'element pedagogique Apogee correspondant:
    code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
    # coef UE, utilise seulement si l'option use_ue_coefs est activée:
    coefficient = db.Column(db.Float)

    color = db.Column(db.Text())

    # relations
    matieres = db.relationship("Matiere", lazy="dynamic", backref="ue")
    modules = db.relationship("Module", lazy="dynamic", backref="ue")

    def __repr__(self):
        return f"""<{self.__class__.__name__}(id={self.id}, formation_id={
            self.formation_id}, acronyme='{self.acronyme}', semestre_idx={
            self.semestre_idx} {
            'EXTERNE' if self.is_external else ''})>"""

    def to_dict(self):
        """as a dict, with the same conversions as in ScoDoc7
        (except ECTS: keep None)
        """
        e = dict(self.__dict__)
        e.pop("_sa_instance_state", None)
        # ScoDoc7 output_formators
        e["ue_id"] = self.id
        e["numero"] = e["numero"] if e["numero"] else 0
        e["ects"] = e["ects"]
        e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0
        e["code_apogee"] = e["code_apogee"] or ""  # pas de None
        return e

    def is_locked(self):
        """True if UE should not be modified
        (contains modules used in a locked formsemestre)
        """
        # XXX todo : à ré-écrire avec SQLAlchemy
        from app.scodoc import sco_edit_ue

        return sco_edit_ue.ue_is_locked(self.id)

    def guess_semestre_idx(self) -> None:
        """Lorsqu'on prend une ancienne formation non APC,
        les UE n'ont pas d'indication de semestre.
        Cette méthode fixe le semestre en prenant celui du premier module,
        ou à défaut le met à 1.
        """
        if self.semestre_idx is None:
            module = self.modules.first()
            if module is None:
                self.semestre_idx = 1
            else:
                self.semestre_idx = module.semestre_id
            db.session.add(self)
            db.session.commit()

    def get_ressources(self):
        "Liste des modules ressources rattachés à cette UE"
        return self.modules.filter_by(module_type=scu.ModuleType.RESSOURCE).all()

    def get_saes(self):
        "Liste des modules SAE rattachés à cette UE"
        return self.modules.filter_by(module_type=scu.ModuleType.SAE).all()

    def get_modules_not_apc(self):
        "Listes des modules non SAE et non ressource (standards, mais aussi bonus...)"
        return self.modules.filter(
            (Module.module_type != scu.ModuleType.SAE),
            (Module.module_type != scu.ModuleType.RESSOURCE),
        ).all()