from django.db import models
from django.db.models import JSONField
from django.dispatch import receiver
from django.contrib.postgres.fields import ArrayField
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError

LEVEL_CHOICES = [
    (1, 'Très Petite Section (TPS)'),
    (2, 'Petite Section (PS)'),
    (3, 'Moyenne Section (MS)'),
    (4, 'Grande Section (GS)'),
    (5, 'Cours Préparatoire (CP)'),
    (6, 'Cours Élémentaire 1 (CE1)'),
    (7, 'Cours Élémentaire 2 (CE2)'),
    (8, 'Cours Moyen 1 (CM1)'),
    (9, 'Cours Moyen 2 (CM2)')
]

class Speciality(models.Model):
    name = models.CharField(max_length=100)
    updated_date = models.DateTimeField(auto_now=True)
    color_code = models.CharField(max_length=7, default='#FFFFFF')
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='specialities')

    def __str__(self):
        return self.name

class Teacher(models.Model):
    last_name = models.CharField(max_length=100)
    first_name = models.CharField(max_length=100)
    specialities = models.ManyToManyField(Speciality, blank=True)
    profile_role = models.OneToOneField('Auth.ProfileRole', on_delete=models.CASCADE, related_name='teacher_profile', null=True, blank=True)
    updated_date = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f"{self.last_name} {self.first_name}"

class SchoolClass(models.Model):
    PLANNING_TYPE_CHOICES = [
        (1, 'Annuel'),
        (2, 'Semestriel'),
        (3, 'Trimestriel')
    ]

    atmosphere_name = models.CharField(max_length=255, null=True, blank=True)
    age_range = models.JSONField(null=True, blank=True)
    number_of_students = models.PositiveIntegerField(null=True, blank=True)
    teaching_language = models.CharField(max_length=255, blank=True)
    school_year = models.CharField(max_length=9, blank=True)
    created_at = models.DateTimeField(auto_now_add=True, null=True)
    updated_date = models.DateTimeField(auto_now=True)
    teachers = models.ManyToManyField(Teacher, blank=True)
    levels = models.ManyToManyField('Common.Level', blank=True, related_name='school_classes')
    type = models.IntegerField(choices=PLANNING_TYPE_CHOICES, default=1)
    time_range = models.JSONField(default=list)
    opening_days = ArrayField(models.IntegerField(), default=list)
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='school_classes')

    def __str__(self):
        return self.atmosphere_name

class Planning(models.Model):
    level = models.IntegerField(choices=LEVEL_CHOICES, null=True, blank=True)
    school_class = models.ForeignKey(SchoolClass, null=True, blank=True, related_name='plannings', on_delete=models.CASCADE)
    schedule = JSONField(default=dict)

    def __str__(self):
        return f'Planning for {self.level} of {self.school_class.atmosphere_name}'

class DiscountType(models.IntegerChoices):
    CURRENCY = 0, 'Currency'
    PERCENT = 1, 'Percent'

class FeeType(models.IntegerChoices):
    REGISTRATION_FEE = 0, 'Registration Fee'
    TUITION_FEE = 1, 'Tuition Fee'

class Discount(models.Model):
    name = models.CharField(max_length=255, null=True, blank=True)
    amount = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    description = models.TextField(blank=True)
    discount_type = models.IntegerField(choices=DiscountType.choices, default=DiscountType.CURRENCY)
    type = models.IntegerField(choices=FeeType.choices, default=FeeType.REGISTRATION_FEE)
    updated_at = models.DateTimeField(auto_now=True)
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='discounts')

    def __str__(self):
        return self.name

class Fee(models.Model):
    name = models.CharField(max_length=255, null=True, blank=True)
    base_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    description = models.TextField(blank=True)
    is_active = models.BooleanField(default=True)
    updated_at = models.DateTimeField(auto_now=True)
    type = models.IntegerField(choices=FeeType.choices, default=FeeType.REGISTRATION_FEE)
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='fees')

    def __str__(self):
        return self.name

class PaymentPlan(models.Model):
    plan_type = models.ForeignKey('Common.PaymentPlanType', on_delete=models.PROTECT, related_name='payment_plans')
    due_dates = ArrayField(models.DateField(), null=True, blank=True)
    type = models.IntegerField(choices=FeeType.choices, default=FeeType.REGISTRATION_FEE)
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='payment_plans')

    def __str__(self):
        return f"{self.plan_type.label} - {self.get_type_display()}"

class PaymentMode(models.Model):
    mode = models.ForeignKey('Common.PaymentModeType', on_delete=models.PROTECT, related_name='payment_modes')
    type = models.IntegerField(choices=FeeType.choices, default=FeeType.REGISTRATION_FEE)
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='payment_modes')

    def __str__(self):
        return f"{self.mode.label} - {self.get_type_display()}"

class Competency(models.Model):
    name = models.TextField()
    end_of_cycle = models.BooleanField(default=False, null=True, blank=True)
    level = models.CharField(max_length=50, null=True, blank=True)
    category = models.ForeignKey('Common.Category', on_delete=models.CASCADE, related_name='competencies')

    establishments = models.ManyToManyField(
        'Establishment.Establishment',
        through='School.EstablishmentCompetency',
        related_name='competencies',
        blank=True
    )

    def __str__(self):
        return self.name
    
class EstablishmentCompetency(models.Model):
    """
    Relation entre un établissement et une compétence.
    Peut référencer une compétence de référence OU une compétence custom propre à l'établissement.
    """
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE)
    competency = models.ForeignKey(
        'School.Competency', on_delete=models.CASCADE, null=True, blank=True,
        help_text="Compétence de référence (optionnelle si custom)"
    )
    custom_name = models.TextField(null=True, blank=True, help_text="Nom de la compétence custom")
    custom_category = models.ForeignKey(
        'Common.Category', on_delete=models.CASCADE, null=True, blank=True,
        help_text="Catégorie de la compétence custom"
    )
    is_required = models.BooleanField(default=True)

    class Meta:
        unique_together = ('establishment', 'competency', 'custom_name', 'custom_category')

    def __str__(self):
        if self.competency:
            return f"{self.establishment.name} - {self.competency.name}"
        return f"{self.establishment.name} - {self.custom_name} (custom)"


class Evaluation(models.Model):
    """
    Définition d'une évaluation (contrôle, examen, etc.) associée à une matière et une classe.
    """
    name = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    speciality = models.ForeignKey(Speciality, on_delete=models.CASCADE, related_name='evaluations')
    school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE, related_name='evaluations')
    period = models.CharField(max_length=20, help_text="Période ex: T1_2025-2026, S1_2025-2026, A_2025-2026")
    date = models.DateField(null=True, blank=True)
    max_score = models.DecimalField(max_digits=5, decimal_places=2, default=20)
    coefficient = models.DecimalField(max_digits=3, decimal_places=2, default=1)
    establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='evaluations')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-date', '-created_at']

    def __str__(self):
        return f"{self.name} - {self.speciality.name} ({self.school_class.atmosphere_name})"