# -*- coding: UTF-8 -*

"""Notes, décisions de jury
"""

from app import db
from app import log
from app.models import SHORT_STR_LEN
from app.models import CODE_STR_LEN
from app.models.events import Scolog
from app.scodoc import sco_cache
from app.scodoc import sco_utils as scu
from app.scodoc.codes_cursus import CODES_UE_VALIDES


class ScolarFormSemestreValidation(db.Model):
    """Décisions de jury (sur semestre ou UEs)"""

    __tablename__ = "scolar_formsemestre_validation"
    # Assure unicité de la décision:
    __table_args__ = (db.UniqueConstraint("etudid", "formsemestre_id", "ue_id"),)

    id = db.Column(db.Integer, primary_key=True)
    formsemestre_validation_id = db.synonym("id")
    etudid = db.Column(
        db.Integer,
        db.ForeignKey("identite.id", ondelete="CASCADE"),
        index=True,
    )
    formsemestre_id = db.Column(
        db.Integer,
        db.ForeignKey("notes_formsemestre.id"),
        index=True,
    )
    ue_id = db.Column(
        db.Integer,
        db.ForeignKey("notes_ue.id"),
        index=True,
    )
    code = db.Column(db.String(CODE_STR_LEN), nullable=False, index=True)
    # NULL pour les UE, True|False pour les semestres:
    assidu = db.Column(db.Boolean)
    event_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
    # NULL sauf si compense un semestre: (pas utilisé pour BUT)
    compense_formsemestre_id = db.Column(
        db.Integer,
        db.ForeignKey("notes_formsemestre.id"),
    )
    moy_ue = db.Column(db.Float)
    # (normalement NULL) indice du semestre, utile seulement pour
    # UE "antérieures" et si la formation définit des UE utilisées
    # dans plusieurs semestres (cas R&T IUTV v2)
    semestre_id = db.Column(db.Integer)
    # Si UE validée dans le cursus d'un autre etablissement
    is_external = db.Column(
        db.Boolean, default=False, server_default="false", index=True
    )

    ue = db.relationship("UniteEns", lazy="select", uselist=False)
    etud = db.relationship("Identite", backref="validations")
    formsemestre = db.relationship(
        "FormSemestre", lazy="select", uselist=False, foreign_keys=[formsemestre_id]
    )

    def __repr__(self):
        return f"""{self.__class__.__name__}(sem={self.formsemestre_id}, etuid={
            self.etudid}, code={self.code}, ue={self.ue}, moy_ue={self.moy_ue})"""

    def __str__(self):
        if self.ue_id:
            # Note: si l'objet vient d'être créé, ue_id peut exister mais pas ue !
            return f"""décision sur UE {self.ue.acronyme if self.ue else self.ue_id
                                        } ({self.ue_id}): {self.code}"""
        return f"""décision sur semestre {self.formsemestre.titre_mois()} du {
                self.event_date.strftime("%d/%m/%Y")}"""

    def delete(self):
        "Efface cette validation"
        log(f"{self.__class__.__name__}.delete({self})")
        etud = self.etud
        db.session.delete(self)
        db.session.commit()
        sco_cache.invalidate_formsemestre_etud(etud)

    def to_dict(self) -> dict:
        "as a dict"
        d = dict(self.__dict__)
        d.pop("_sa_instance_state", None)
        return d

    def html(self, detail=False) -> str:
        "Affichage html"
        if self.ue_id is not None:
            moyenne = (
                f", moyenne {scu.fmt_note(self.moy_ue)}/20 "
                if self.moy_ue is not None
                else ""
            )
            link = (
                self.formsemestre.html_link_status(
                    label=f"{self.formsemestre.titre_formation(with_sem_idx=1)}",
                    title=self.formsemestre.titre_annee(),
                )
                if self.formsemestre
                else "externe/antérieure"
            )
            return f"""Validation
                {'<span class="redboldtext">externe</span>' if self.is_external else ""}
                de l'UE <b>{self.ue.acronyme}</b>
                {('parcours <span class="parcours">'
                  + ", ".join([p.code for p in self.ue.parcours]))
                  + "</span>"
                  if self.ue.parcours else ""}
                {("émise par " + link)}
                : <b>{self.code}</b>{moyenne}
                le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")}
            """
        else:
            return f"""Validation du semestre S{
                self.formsemestre.semestre_id if self.formsemestre else "?"}
                {self.formsemestre.html_link_status() if self.formsemestre else ""}
                : <b>{self.code}</b>
                le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")}
            """

    def ects(self) -> float:
        "Les ECTS acquis par cette validation. (0 si ce n'est pas une validation d'UE)"
        return (
            self.ue.ects
            if (self.ue is not None) and (self.code in CODES_UE_VALIDES)
            else 0.0
        )


class ScolarAutorisationInscription(db.Model):
    """Autorisation d'inscription dans un semestre"""

    __tablename__ = "scolar_autorisation_inscription"
    id = db.Column(db.Integer, primary_key=True)
    autorisation_inscription_id = db.synonym("id")

    etudid = db.Column(
        db.Integer,
        db.ForeignKey("identite.id", ondelete="CASCADE"),
    )
    formation_code = db.Column(db.String(SHORT_STR_LEN), nullable=False)
    # Indice du semestre où on peut s'inscrire:
    semestre_id = db.Column(db.Integer)
    date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
    origin_formsemestre_id = db.Column(
        db.Integer,
        db.ForeignKey("notes_formsemestre.id"),
    )
    origin_formsemestre = db.relationship("FormSemestre", lazy="select", uselist=False)

    def __repr__(self) -> str:
        return f"""{self.__class__.__name__}(id={self.id}, etudid={
            self.etudid}, semestre_id={self.semestre_id})"""

    def to_dict(self) -> dict:
        "as a dict"
        d = dict(self.__dict__)
        d.pop("_sa_instance_state", None)
        return d

    def html(self) -> str:
        "Affichage html"
        link = (
            self.origin_formsemestre.html_link_status(
                label=f"{self.origin_formsemestre.titre_formation(with_sem_idx=1)}",
                title=self.origin_formsemestre.titre_annee(),
            )
            if self.origin_formsemestre
            else "externe/antérieure"
        )
        return f"""Autorisation de passage vers <b>S{self.semestre_id}</b> émise par
            {link}
            le {self.date.strftime("%d/%m/%Y")} à {self.date.strftime("%Hh%M")}
        """

    @classmethod
    def autorise_etud(
        cls,
        etudid: int,
        formation_code: str,
        origin_formsemestre_id: int,
        semestre_id: int,
    ):
        """Ajoute une autorisation"""
        autorisation = cls(
            etudid=etudid,
            formation_code=formation_code,
            origin_formsemestre_id=origin_formsemestre_id,
            semestre_id=semestre_id,
        )
        db.session.add(autorisation)
        Scolog.logdb(
            "autorise_etud", etudid=etudid, msg=f"Passage vers S{semestre_id}: autorisé"
        )
        log(f"ScolarAutorisationInscription: recording {autorisation}")

    @classmethod
    def delete_autorisation_etud(
        cls,
        etudid: int,
        origin_formsemestre_id: int,
    ):
        """Efface les autorisations de cet étudiant venant du sem. origine"""
        autorisations = cls.query.filter_by(
            etudid=etudid, origin_formsemestre_id=origin_formsemestre_id
        )
        for autorisation in autorisations:
            db.session.delete(autorisation)
            log(f"ScolarAutorisationInscription: deleting {autorisation}")
            Scolog.logdb(
                "autorise_etud",
                etudid=etudid,
                msg=f"Passage vers S{autorisation.semestre_id}: effacé",
            )
        db.session.flush()
