from django.db import models
from django.utils.timezone import now
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from datetime import datetime
import logging
import os

logger = logging.getLogger("SubscriptionModels")

class Language(models.Model):
    """
    Représente une langue parlée par l’élève.
    """
    id = models.AutoField(primary_key=True)
    label = models.CharField(max_length=200, default="")

    def __str__(self):
        return "LANGUAGE"

class Guardian(models.Model):
    """
    Représente un responsable légal (parent/tuteur) d’un élève.
    """
    last_name = models.CharField(max_length=200, null=True, blank=True)
    first_name = models.CharField(max_length=200, null=True, blank=True)
    birth_date = models.DateField(null=True, blank=True)
    address = models.CharField(max_length=200, default="", blank=True)
    phone = models.CharField(max_length=200, default="", blank=True)
    profession = models.CharField(max_length=200, default="", blank=True)
    profile_role = models.OneToOneField('Auth.ProfileRole', on_delete=models.CASCADE, related_name='guardian_profile', null=True, blank=True)

    @property
    def email(self):
        """
        Retourne l'email du profil associé via le ProfileRole.
        """
        if self.profile_role and self.profile_role.profile:
            return self.profile_role.profile.email
        return None

    def __str__(self):
        return self.last_name + "_" + self.first_name

class Sibling(models.Model):
    """
    Représente un frère ou une sœur d’un élève.
    """
    last_name = models.CharField(max_length=200, null=True, blank=True)
    first_name = models.CharField(max_length=200, null=True, blank=True)
    birth_date = models.DateField(null=True, blank=True)

    def __str__(self):
        return "SIBLING"

def registration_photo_upload_to(instance, filename):
    """
    Génère le chemin de stockage pour la photo élève.
    Structure : Etablissement/dossier_NomEleve_PrenomEleve/filename
    """
    register_form = getattr(instance, 'registrationform', None)
    if register_form and register_form.establishment:
        est_name = register_form.establishment.name
    elif instance.associated_class and instance.associated_class.establishment:
        est_name = instance.associated_class.establishment.name
    else:
        est_name = "unknown_establishment"

    student_last = instance.last_name if instance and instance.last_name else "unknown"
    student_first = instance.first_name if instance and instance.first_name else "unknown"
    return f"{est_name}/dossier_{student_last}_{student_first}/{filename}"

def registration_bilan_form_upload_to(instance, filename):
    """
    Génère le chemin de stockage pour les bilans de compétences.
    Structure : Etablissement/dossier_NomEleve_PrenomEleve/filename
    """
    register_form = getattr(instance.student, 'registrationform', None)
    if register_form and register_form.establishment:
        est_name = register_form.establishment.name
    elif instance.student.associated_class and instance.student.associated_class.establishment:
        est_name = instance.student.associated_class.establishment.name
    else:
        est_name = "unknown_establishment"

    student_last = instance.student.last_name if instance.student else "unknown"
    student_first = instance.student.first_name if instance.student else "unknown"
    return f"{est_name}/dossier_{student_last}_{student_first}/{filename}"

class BilanCompetence(models.Model):
    student = models.ForeignKey('Subscriptions.Student', on_delete=models.CASCADE, related_name='bilans')
    file = models.FileField(upload_to=registration_bilan_form_upload_to, null=True, blank=True)
    period = models.CharField(max_length=20, help_text="Période ex: T1-2024_2025, S1-2024_2025, A-2024_2025")
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.student} - {self.period}"

class Student(models.Model):
    """
    Représente l’élève inscrit ou en cours d’inscription.
    """
    class StudentGender(models.IntegerChoices):
        NONE = 0, _('Sélection du genre')
        MALE = 1, _('Garçon')
        FEMALE = 2, _('Fille')

    class StudentLevel(models.IntegerChoices):
        NONE = 0, _('Sélection du niveau')
        TPS = 1, _('TPS - Très Petite Section')
        PS = 2, _('PS - Petite Section')
        MS = 3, _('MS - Moyenne Section')
        GS = 4, _('GS - Grande Section')
        CP = 5, _('CP')
        CE1 = 6, _('CE1')
        CE2 = 7, _('CE2')
        CM1 = 8, _('CM1')
        CM2 = 9, _('CM2')

    photo = models.FileField(
        upload_to=registration_photo_upload_to,
        null=True,
        blank=True
    )
    last_name = models.CharField(max_length=200, default="")
    first_name = models.CharField(max_length=200, default="")
    gender = models.IntegerField(choices=StudentGender, default=StudentGender.NONE, blank=True)
    level = models.ForeignKey('Common.Level', on_delete=models.SET_NULL, null=True, blank=True, related_name='students')
    nationality = models.CharField(max_length=200, default="", blank=True)
    address = models.CharField(max_length=200, default="", blank=True)
    birth_date = models.DateField(null=True, blank=True)
    birth_place = models.CharField(max_length=200, default="", blank=True)
    birth_postal_code = models.IntegerField(default=0, blank=True)
    attending_physician = models.CharField(max_length=200, default="", blank=True)

    # Many-to-Many Relationship
    profiles = models.ManyToManyField('Auth.Profile', blank=True)

    # Many-to-Many Relationship
    guardians = models.ManyToManyField('Subscriptions.Guardian', blank=True)

    # Many-to-Many Relationship
    siblings = models.ManyToManyField('Subscriptions.Sibling', blank=True)

    # Many-to-Many Relationship
    registration_files = models.ManyToManyField('Subscriptions.RegistrationSchoolFileTemplate', blank=True, related_name='students')

    # Many-to-Many Relationship
    spoken_languages = models.ManyToManyField('Subscriptions.Language', blank=True)

    # One-to-Many Relationship
    associated_class = models.ForeignKey('School.SchoolClass', on_delete=models.SET_NULL, null=True, blank=True, related_name='students')

    # Audit fields
    created_at = models.DateTimeField(auto_now_add=True, null=True)
    updated_at = models.DateTimeField(auto_now=True, null=True)

    def __str__(self):
        return self.last_name + "_" + self.first_name

    def getSpokenLanguages(self):
        """
        Retourne la liste des langues parlées par l’élève.
        """
        return self.spoken_languages.all()

    def getMainGuardian(self):
        """
        Retourne le responsable légal principal de l’élève.
        """
        return self.guardians.all()[0]

    def getGuardians(self):
        """
        Retourne tous les responsables légaux de l’élève.
        """
        return self.guardians.all()

    def getProfiles(self):
        """
        Retourne les profils utilisateurs liés à l’élève.
        """
        return self.profiles.all()

    def getSiblings(self):
        """
        Retourne les frères et sœurs de l’élève.
        """
        return self.siblings.all()

    def getNumberOfSiblings(self):
        """
        Retourne le nombre de frères et sœurs.
        """
        return self.siblings.count()

    def get_photo_url(self):
        """
        Retourne le chemin correct de la photo pour le template HTML.
        Si la photo n'existe pas, retourne le chemin de l'image par défaut.
        """
        if self.photo and hasattr(self.photo, 'url'):
            # Retourne l'URL complète de la photo
            return self.photo.url

    @property
    def age(self):
        if self.birth_date:
            today = datetime.today()
            years = today.year - self.birth_date.year
            months = today.month - self.birth_date.month
            if today.day < self.birth_date.day:
                months -= 1
            if months < 0:
                years -= 1
                months += 12

            # Determine the age format
            if 6 <= months <= 12:
                return f"{years} years 1/2"
            else:
                return f"{years} years"
        return None

    @property
    def formatted_birth_date(self):
        if self.birth_date:
            return self.birth_date.strftime('%d-%m-%Y')
        return None

class RegistrationFileGroup(models.Model):
    name = models.CharField(max_length=255, default="")
    description = models.TextField(blank=True, null=True)
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='file_group', null=True, blank=True)

    def __str__(self):
        return self.name

    def __str__(self):
        return f'{self.group.name} - {self.id}'

def registration_form_file_upload_to(instance, filename):
    """
    Génère le chemin de stockage pour les fichiers du dossier d'inscription.
    Structure : Etablissement/dossier_NomEleve_PrenomEleve/filename
    """
    est_name = instance.establishment.name if instance.establishment else "unknown_establishment"
    student_last = instance.student.last_name if instance.student else "unknown"
    student_first = instance.student.first_name if instance.student else "unknown"
    return f"{est_name}/dossier_{student_last}_{student_first}/{filename}"

def _delete_file_if_exists(file_field):
    """
    Supprime le fichier physique s'il existe.
    Utile pour éviter les suffixes automatiques Django lors du remplacement.
    """
    if file_field and file_field.name:
        try:
            if hasattr(file_field, 'path') and os.path.exists(file_field.path):
                os.remove(file_field.path)
                logger.debug(f"Fichier supprimé: {file_field.path}")
        except Exception as e:
            logger.error(f"Erreur lors de la suppression du fichier {file_field.name}: {e}")

class RegistrationForm(models.Model):
    class RegistrationFormStatus(models.IntegerChoices):
        RF_IDLE = 0, _('Pas de dossier d\'inscription')
        RF_INITIALIZED = 1, _('Dossier d\'inscription initialisé')
        RF_SENT = 2, _('Dossier d\'inscription envoyé')
        RF_UNDER_REVIEW = 3, _('Dossier d\'inscription en cours de validation')
        RF_TO_BE_FOLLOWED_UP = 4, _('Dossier d\'inscription à relancer')
        RF_VALIDATED = 5, _('Dossier d\'inscription validé')
        RF_ARCHIVED = 6, _('Dossier d\'inscription archivé')
        RF_SEPA_SENT = 7, _('Mandat SEPA envoyé')
        RF_SEPA_TO_SEND = 8, _('Mandat SEPA à envoyer')

    # One-to-One Relationship
    student = models.OneToOneField(Student, on_delete=models.CASCADE, primary_key=True)
    status = models.IntegerField(choices=RegistrationFormStatus, default=RegistrationFormStatus.RF_IDLE)
    created_at = models.DateTimeField(auto_now_add=True, null=True)
    last_update = models.DateTimeField(auto_now=True)
    school_year = models.CharField(max_length=9, default="", blank=True)
    notes = models.CharField(max_length=200, blank=True)
    registration_link_code = models.CharField(max_length=200, default="", blank=True)
    registration_file = models.FileField(
        upload_to=registration_form_file_upload_to,
        null=True,
        blank=True
    )
    sepa_file = models.FileField(
        upload_to=registration_form_file_upload_to,
        null=True,
        blank=True
    )
    fusion_file = models.FileField(
        upload_to=registration_form_file_upload_to,
        null=True,
        blank=True
    )
    associated_rf = models.CharField(max_length=200, default="", blank=True)

    # Many-to-Many Relationship
    fees = models.ManyToManyField('School.Fee', blank=True, related_name='register_forms')

    # Many-to-Many Relationship
    discounts = models.ManyToManyField('School.Discount', blank=True, related_name='register_forms')
    fileGroup = models.ForeignKey(RegistrationFileGroup,
                                 on_delete=models.SET_NULL,
                                 related_name='register_forms',
                                 null=True,
                                 blank=True)

    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='register_forms')
    registration_payment = models.ForeignKey('School.PaymentMode', on_delete=models.SET_NULL, null=True, blank=True, related_name='registration_payment_modes_forms')
    tuition_payment = models.ForeignKey('School.PaymentMode', on_delete=models.SET_NULL, null=True, blank=True, related_name='tuition_payment_modes_forms')
    registration_payment_plan = models.ForeignKey('School.PaymentPlan', on_delete=models.SET_NULL, null=True, blank=True, related_name='registration_payment_plans_forms')
    tuition_payment_plan = models.ForeignKey('School.PaymentPlan', on_delete=models.SET_NULL, null=True, blank=True, related_name='tuition_payment_plans_forms')

    def __str__(self):
        return "RF_" + self.student.last_name + "_" + self.student.first_name

    def save(self, *args, **kwargs):
        # Préparer le flag de création / changement de fileGroup
        was_new = self.pk is None
        old_fileGroup = None
        if not was_new:
            try:
                old_instance = RegistrationForm.objects.get(pk=self.pk)
                old_fileGroup = old_instance.fileGroup
            except RegistrationForm.DoesNotExist:
                old_fileGroup = None

        # Supprimer les anciens fichiers si remplacés (évite les suffixes Django)
        if self.pk:  # Si l'objet existe déjà dans la base de données
            try:
                old_instance = RegistrationForm.objects.get(pk=self.pk)
                
                # Gestion du sepa_file
                if old_instance.sepa_file and old_instance.sepa_file != self.sepa_file:
                    _delete_file_if_exists(old_instance.sepa_file)
                
                # Gestion du registration_file
                if old_instance.registration_file and old_instance.registration_file != self.registration_file:
                    _delete_file_if_exists(old_instance.registration_file)
                
                # Gestion du fusion_file
                if old_instance.fusion_file and old_instance.fusion_file != self.fusion_file:
                    _delete_file_if_exists(old_instance.fusion_file)
                    
            except RegistrationForm.DoesNotExist:
                pass  # L'objet n'existe pas encore, rien à supprimer

        # Appeler la méthode save originale
        super().save(*args, **kwargs)

        # Après save : si nouveau ou changement de fileGroup -> créer les templates
        fileGroup_changed = (self.fileGroup is not None) and (old_fileGroup is None or (old_fileGroup and old_fileGroup.id != self.fileGroup.id))
        if was_new or fileGroup_changed:
            try:
                import Subscriptions.util as util
                created = util.create_templates_for_registration_form(self)
                if created:
                    logger.info("Created %d templates for RegistrationForm %s", len(created), self.pk)
            except Exception as e:
                logger.exception("Error creating templates for RegistrationForm %s: %s", self.pk, e)

#############################################################
####################### MASTER FILES ########################
#############################################################

####### Formulaires masters (documents école, à signer ou pas) #######
def registration_school_file_master_upload_to(instance, filename):
    # Stocke les fichiers masters dans un dossier dédié
    # Utilise l'ID si le nom n'est pas encore disponible
    est_name = None
    if instance.establishment and instance.establishment.name:
        est_name = instance.establishment.name
    else:
        # fallback si pas d'établissement (devrait être rare)
        est_name = "unknown_establishment"
    return f"{est_name}/Formulaires/{filename}"

class RegistrationSchoolFileMaster(models.Model):
    groups = models.ManyToManyField(RegistrationFileGroup, related_name='school_file_masters', blank=True)
    name = models.CharField(max_length=255, default="")
    is_required = models.BooleanField(default=False)
    requires_electronic_signature = models.BooleanField(default=False, help_text="Si activé, le parent devra signer électroniquement ce document")
    formMasterData = models.JSONField(default=list, blank=True, null=True)
    file = models.FileField(
        upload_to=registration_school_file_master_upload_to,
        null=True,
        blank=True,
        help_text="Fichier du formulaire existant (PDF, DOC, etc.)"
    )
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='school_file_masters', null=True, blank=True)

    def __str__(self):
        return f'{self.name} - {self.id}'

    @property
    def file_url(self):
        if self.file and hasattr(self.file, 'url'):
            return self.file.url
        return None

    def save(self, *args, **kwargs):
        affected_rf_ids = set()
        is_new = self.pk is None

        # Log création ou modification du master
        if is_new:
            logger.info(f"[FormPerso] Création master '{self.name}' pour établissement '{self.establishment}'")
        else:
            logger.info(f"[FormPerso] Modification master '{self.name}' (id={self.pk}) pour établissement '{self.establishment}'")

        # --- Suppression de l'ancien fichier master si le nom change (form existant ou dynamique) ---
        if self.pk:
            try:
                old = RegistrationSchoolFileMaster.objects.get(pk=self.pk)
                if old.file and old.file.name:
                    old_filename = os.path.basename(old.file.name)
                    # Nouveau nom selon le type (dynamique ou existant)
                    if (
                        self.formMasterData
                        and isinstance(self.formMasterData, dict)
                        and self.formMasterData.get("fields")
                    ):
                        # Si un fichier source est déjà présent, conserver son extension.
                        extension = os.path.splitext(old_filename)[1] or '.pdf'
                        new_filename = f"{self.name}{extension}"
                    else:
                        # Pour les forms existants, le nom attendu est self.name + extension du fichier existant
                        extension = os.path.splitext(old_filename)[1]
                        new_filename = f"{self.name}{extension}" if extension else self.name
                    if new_filename and old_filename != new_filename:
                        old_file_path = old.file.path
                        if os.path.exists(old_file_path):
                            try:
                                os.remove(old_file_path)
                                logger.info(f"[FormPerso] Suppression de l'ancien fichier master: {old_file_path}")
                            except Exception as e:
                                logger.error(f"[FormPerso] Erreur suppression ancien fichier master: {e}")
                    # Correction du nom du fichier pour éviter le suffixe random
                    if (
                        not self.formMasterData
                        or not (isinstance(self.formMasterData, dict) and self.formMasterData.get("fields"))
                    ):
                        # Si le fichier existe et le nom ne correspond pas, renommer le fichier physique et mettre à jour le FileField
                        if self.file and self.file.name:
                            current_filename = os.path.basename(self.file.name)
                            current_path = self.file.path
                            expected_filename = new_filename
                            expected_path = os.path.join(os.path.dirname(current_path), expected_filename)
                            if current_filename != expected_filename:
                                try:
                                    if os.path.exists(current_path):
                                        os.rename(current_path, expected_path)
                                        self.file.name = os.path.join(os.path.dirname(self.file.name), expected_filename).replace("\\", "/")
                                        logger.info(f"[FormPerso] Renommage du fichier master: {current_path} -> {expected_path}")
                                except Exception as e:
                                    logger.error(f"[FormPerso] Erreur lors du renommage du fichier master: {e}")
            except RegistrationSchoolFileMaster.DoesNotExist:
                pass

        # IMPORTANT: pour les formulaires dynamiques, le fichier du master doit
        # rester le document source uploadé (PDF/image). La génération du PDF final
        # est faite au niveau des templates (par élève), pas sur le master.

        super().save(*args, **kwargs)

        # Synchronisation des templates pour tous les dossiers d'inscription concernés (création ou modification)
        try:
            # Import local pour éviter le circular import
            from Subscriptions.util import create_templates_for_registration_form
            from Subscriptions.models import RegistrationForm, RegistrationSchoolFileTemplate
            # Détermination des RF concernés
            if is_new:
                new_groups = set(self.groups.values_list('id', flat=True))
                affected_rf_ids.update(
                    RegistrationForm.objects.filter(fileGroup__in=list(new_groups)).values_list('pk', flat=True)
                )
            else:
                try:
                    old = RegistrationSchoolFileMaster.objects.get(pk=self.pk)
                    old_groups = set(old.groups.values_list('id', flat=True))
                    new_groups = set(self.groups.values_list('id', flat=True))
                    affected_rf_ids.update(
                        RegistrationForm.objects.filter(fileGroup__in=list(old_groups | new_groups)).values_list('pk', flat=True)
                    )
                    form_data_changed = (
                        old.formMasterData != self.formMasterData
                        and self.formMasterData
                        and isinstance(self.formMasterData, dict)
                        and self.formMasterData.get("fields")
                    )
                    name_changed = old.name != self.name
                    if form_data_changed or name_changed:
                        logger.info(f"[FormPerso] Modification du contenu du master '{self.name}' (id={self.pk})")
                except RegistrationSchoolFileMaster.DoesNotExist:
                    pass

            # Pour chaque RF concerné, régénérer les templates
            for rf_id in affected_rf_ids:
                try:
                    rf = RegistrationForm.objects.get(pk=rf_id)
                    logger.info(f"[FormPerso] Synchronisation template pour élève '{rf.student.last_name}_{rf.student.first_name}' (RF id={rf.pk}) suite à modification/ajout du master '{self.name}'")
                    create_templates_for_registration_form(rf)
                except Exception as e:
                    logger.error(f"Erreur lors de la synchronisation des templates pour RF {rf_id} après modification du master {self.pk}: {e}")
        except Exception as e:
            logger.error(f"Erreur globale lors de la synchronisation des templates après modification du master {self.pk}: {e}")

    def delete(self, *args, **kwargs):
        logger.info(f"[FormPerso] Suppression master '{self.name}' (id={self.pk}) et tous ses templates")
        # Import local pour éviter le circular import
        from Subscriptions.models import RegistrationSchoolFileTemplate
        templates = RegistrationSchoolFileTemplate.objects.filter(master=self)
        for tmpl in templates:
            logger.info(f"[FormPerso] Suppression template '{tmpl.name}' pour élève '{tmpl.registration_form.student.last_name}_{tmpl.registration_form.student.first_name}' (RF id={tmpl.registration_form.pk})")
        if self.file and hasattr(self.file, 'path') and os.path.exists(self.file.path):
            try:
                self.file.delete(save=False)
            except Exception as e:
                logger.error(f"Erreur lors de la suppression du fichier master: {e}")
        super().delete(*args, **kwargs)

####### Parent files masters (documents à fournir par les parents) #######
class RegistrationParentFileMaster(models.Model):
    groups = models.ManyToManyField(RegistrationFileGroup, related_name='parent_file_masters', blank=True)
    name = models.CharField(max_length=255, default="")
    description = models.CharField(max_length=500, blank=True, null=True)
    is_required = models.BooleanField(default=False)

############################################################
####################### CLONE FILES ########################
############################################################

def registration_school_file_upload_to(instance, filename):
    """
    Génère le chemin pour les fichiers templates école.
    Structure : Etablissement/dossier_NomEleve_PrenomEleve/filename
    """
    return f"{instance.registration_form.establishment.name}/dossier_{instance.registration_form.student.last_name}_{instance.registration_form.student.first_name}/{filename}"

def registration_parent_file_upload_to(instance, filename):
    """
    Génère le chemin pour les fichiers à fournir par les parents.
    Structure : Etablissement/dossier_NomEleve_PrenomEleve/parent/filename
    """
    return f"{instance.registration_form.establishment.name}/dossier_{instance.registration_form.student.last_name}_{instance.registration_form.student.first_name}/parent/{filename}"

####### Formulaires templates (par dossier d'inscription) #######
class RegistrationSchoolFileTemplate(models.Model):
    master = models.ForeignKey(RegistrationSchoolFileMaster, on_delete=models.CASCADE, related_name='school_file_templates', blank=True)
    slug = models.CharField(max_length=255, default="")
    name = models.CharField(max_length=255, default="")
    registration_form = models.ForeignKey(RegistrationForm, on_delete=models.CASCADE, related_name='school_file_templates', blank=True)
    file = models.FileField(null=True,blank=True, upload_to=registration_school_file_upload_to)
    formTemplateData = models.JSONField(default=list, blank=True, null=True)
    # Tri-etat: None=en attente, True=valide, False=refuse
    isValidated = models.BooleanField(null=True, blank=True, default=None)
    # Signature électronique (base64 SVG ou PNG)
    electronic_signature = models.TextField(null=True, blank=True, help_text="Signature électronique encodée en base64")
    electronic_signature_date = models.DateTimeField(null=True, blank=True, help_text="Date de la signature électronique")

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        # Supprimer l'ancien fichier si remplacé (évite les suffixes Django)
        if self.pk:
            try:
                old_instance = RegistrationSchoolFileTemplate.objects.get(pk=self.pk)
                if old_instance.file and old_instance.file != self.file:
                    _delete_file_if_exists(old_instance.file)
            except RegistrationSchoolFileTemplate.DoesNotExist:
                pass
        super().save(*args, **kwargs)

    @staticmethod
    def get_files_from_rf(register_form_id):
        """
        Récupère tous les fichiers liés à un dossier d’inscription donné.
        Ignore les fichiers qui n'existent pas physiquement.
        """
        registration_files = RegistrationSchoolFileTemplate.objects.filter(registration_form=register_form_id)
        filenames = []
        for reg_file in registration_files:
            if reg_file.file and hasattr(reg_file.file, 'path'):
                if os.path.exists(reg_file.file.path):
                    filenames.append(reg_file.file.path)
                else:
                    logger.warning(f"Fichier introuvable ignoré: {reg_file.file.path}")
        return filenames

class StudentCompetency(models.Model):
    student = models.ForeignKey('Subscriptions.Student', on_delete=models.CASCADE, related_name='competency_scores')
    establishment_competency = models.ForeignKey('School.EstablishmentCompetency', on_delete=models.CASCADE, related_name='student_scores')
    score = models.IntegerField(null=True, blank=True)
    comment = models.TextField(blank=True, null=True)
    period = models.CharField(
        max_length=20,
        help_text="Période d'évaluation ex: T1-2024_2025, S1-2024_2025, A-2024_2025",
        default="",
        blank=True
    )
    created_at = models.DateTimeField(auto_now_add=True, null=True)
    updated_at = models.DateTimeField(auto_now=True, null=True)

    class Meta:
        unique_together = ('student', 'establishment_competency', 'period')

    indexes = [
        models.Index(fields=['student', 'establishment_competency', 'period']),
    ]

    def __str__(self):
        return f"{self.student} - {self.establishment_competency} - Score: {self.score} - Period: {self.period}"


class StudentEvaluation(models.Model):
    """
    Note d'un élève pour une évaluation.
    Déplacé depuis School pour éviter les dépendances circulaires.
    """
    student = models.ForeignKey('Subscriptions.Student', on_delete=models.CASCADE, related_name='evaluation_scores')
    evaluation = models.ForeignKey('School.Evaluation', on_delete=models.CASCADE, related_name='student_scores')
    score = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
    comment = models.TextField(blank=True)
    is_absent = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        unique_together = ('student', 'evaluation')

    def __str__(self):
        score_display = 'Absent' if self.is_absent else self.score
        return f"{self.student} - {self.evaluation.name}: {score_display}"

####### Parent files templates (par dossier d'inscription) #######
class RegistrationParentFileTemplate(models.Model):
    master = models.ForeignKey(RegistrationParentFileMaster, on_delete=models.CASCADE, related_name='parent_file_templates', blank=True)
    registration_form = models.ForeignKey(RegistrationForm, on_delete=models.CASCADE, related_name='parent_file_templates', blank=True)
    file = models.FileField(null=True,blank=True, upload_to=registration_parent_file_upload_to)
    # Tri-etat: None=en attente, True=valide, False=refuse
    isValidated = models.BooleanField(null=True, blank=True, default=None)

    def __str__(self):
        return self.master.name if self.master else f"ParentFile_{self.pk}"

    def save(self, *args, **kwargs):
        # Supprimer l'ancien fichier si remplacé (évite les suffixes Django)
        if self.pk:
            try:
                old_instance = RegistrationParentFileTemplate.objects.get(pk=self.pk)
                # Si le fichier change ou est supprimé
                if old_instance.file:
                    if old_instance.file != self.file or not self.file or self.file.name == '':
                        _delete_file_if_exists(old_instance.file)
                        if not self.file or self.file.name == '':
                            self.file = None
            except RegistrationParentFileTemplate.DoesNotExist:
                pass
        super().save(*args, **kwargs)

    @staticmethod
    def get_files_from_rf(register_form_id):
        """
        Récupère tous les fichiers liés à un dossier d’inscription donné.
        """
        registration_files = RegistrationParentFileTemplate.objects.filter(registration_form=register_form_id)
        filenames = []
        for reg_file in registration_files:
            if reg_file.file and hasattr(reg_file.file, 'path'):
                filenames.append(reg_file.file.path)
        return filenames

class AbsenceMoment(models.IntegerChoices):
    MORNING = 1, 'Morning'
    AFTERNOON = 2, 'Afternoon'
    TOTAL = 3, 'Total'

class AbsenceReason(models.IntegerChoices):
    JUSTIFIED_ABSENCE = 1, 'Justified Absence'
    UNJUSTIFIED_ABSENCE = 2, 'Unjustified Absence'
    JUSTIFIED_LATE = 3, 'Justified Late'
    UNJUSTIFIED_LATE = 4, 'Unjustified Late'

class AbsenceManagement(models.Model):
    day = models.DateField(blank=True, null=True)
    moment = models.IntegerField(
        choices=AbsenceMoment.choices,
        default=AbsenceMoment.TOTAL
    )
    reason = models.IntegerField(
        choices=AbsenceReason.choices,
        default=AbsenceReason.UNJUSTIFIED_ABSENCE
    )
    student = models.ForeignKey(
        Student,
        on_delete=models.CASCADE,
        related_name='absences',
        blank=True, null=True
    )
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='absences', blank=True, null=True)
    commentaire = models.TextField(blank=True, null=True)

    def __str__(self):
        return f"{self.student} - {self.day} - {self.get_moment_display()} - {self.get_reason_display()}"