# academics/models.py
"""
Models for academic management including classes, subjects, and attendance.
"""
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _


class SchoolClass(models.Model):
    """
    Represents a class/grade level in the school.
    
    This model stores information about each class, including its level,
    section, academic year, and assigned teachers. Each class can have
    multiple teachers assigned through the ClassSubject junction model.
    
    Attributes:
        code (str): Unique class identifier (e.g., "CL6-A", "CE1-B")
        name (str): Display name of the class (e.g., "Class 6")
        level (str): Educational level from LEVEL_CHOICES
        section (str): Section letter (A, B, C, etc.)
        section_type (str): Type of section (english, french, bilingual)
        capacity (int): Maximum number of students
        room_number (str): Physical classroom identifier
        academic_year (str): Academic year (e.g., "2025-2026")
        class_teacher (ForeignKey): Reference to the homeroom teacher
        
    Example:
        >>> class_6 = SchoolClass.objects.create(
        ...     code="CL6-A",
        ...     name="Class 6",
        ...     level="class6",
        ...     section="A",
        ...     section_type="english",
        ...     capacity=45
        ... )
    """
    
    LEVEL_CHOICES = [
        ('pre_nursery', 'Pre-Nursery'),
        ('nursery1', 'Nursery 1'),
        ('nursery2', 'Nursery 2'),
        ('moyenne_section', 'Moyenne Section'),
        ('grande_section', 'Grande Section'),
        ('sil', 'SIL'),
        ('cp', 'CP'),
        ('ce1', 'CE1'),
        ('ce2', 'CE2'),
        ('cm1', 'CM1'),
        ('cm2', 'CM2'),
        ('class1', 'Class 1'),
        ('class2', 'Class 2'),
        ('class3', 'Class 3'),
        ('class4', 'Class 4'),
        ('class5', 'Class 5'),
        ('class6', 'Class 6'),
    ]
    
    SECTION_TYPE_CHOICES = [
        ('english', 'English Section'),
        ('french', 'French Section'),
        ('bilingual', 'Bilingual Section'),
    ]
    
    code = models.CharField(
        max_length=20, 
        unique=True, 
        help_text="e.g., CL6-A, CE1-B"
    )
    name = models.CharField(
        max_length=50, 
        blank=True, 
        help_text="Display name of the class"
    )
    level = models.CharField(
        max_length=20, 
        choices=LEVEL_CHOICES
    )
    section = models.CharField(
        max_length=10, 
        blank=True, 
        help_text="A, B, C, etc."
    )
    section_type = models.CharField(
        max_length=20, 
        choices=SECTION_TYPE_CHOICES, 
        default='english'
    )
    capacity = models.PositiveIntegerField(
        default=40
    )
    room_number = models.CharField(
        max_length=10, 
        blank=True
    )
    academic_year = models.CharField(
        max_length=9, 
        default="2025-2026"
    )
    
    # Teacher assignments
    class_teacher = models.ForeignKey(
        'staff.Staff', 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        related_name='classes_as_teacher',
        limit_choices_to={'role__in': ['teacher', 'class_teacher']}
    )
    
    class Meta:
        verbose_name = "Class"
        verbose_name_plural = "Classes"
        ordering = ['level', 'section']
        indexes = [
            models.Index(fields=['code']),
            models.Index(fields=['level']),
            models.Index(fields=['section_type']),
        ]
    
    def __str__(self):
        """Return string representation of the class."""
        return self.name or f"{self.get_level_display()} {self.section}"
    
    def save(self, *args, **kwargs):
        """
        Save the class, auto-generating name if not provided.
        """
        if not self.name:
            self.name = str(self)
        super().save(*args, **kwargs)
    
    def get_student_count(self):
        """
        Get the number of students currently enrolled in this class.
        
        Returns:
            int: Count of students with current_class = this class.
        """
        from students.models import Student
        return Student.objects.filter(current_class=self).count()
    
    def get_teachers(self):
        """
        Get all teachers assigned to this class through ClassSubject.
        
        Returns:
            QuerySet: QuerySet of Staff objects assigned to this class.
        """
        return self.teachers.all()


class Subject(models.Model):
    """
    Represents a subject taught in the school.
    
    Subjects can be categorized (core, languages, sciences, etc.) and are
    assigned to classes through the ClassSubject junction model.
    
    Attributes:
        code (str): Unique subject code (e.g., "MATH", "ENG")
        name (str): Subject name in English
        name_fr (str): Subject name in French
        category (str): Subject category from CATEGORY_CHOICES
        description (str): Detailed description of the subject
    """
    
    SUBJECT_CATEGORY_CHOICES = [
        ('core', 'Core Subjects'),
        ('languages', 'Languages'),
        ('sciences', 'Sciences'),
        ('humanities', 'Humanities'),
        ('vocational', 'Vocational Studies'),
        ('arts', 'Arts'),
        ('sports', 'Physical Education'),
    ]
    
    code = models.CharField(
        max_length=10, 
        unique=True
    )
    name = models.CharField(
        max_length=100
    )
    name_fr = models.CharField(
        max_length=100, 
        blank=True
    )
    category = models.CharField(
        max_length=20, 
        choices=SUBJECT_CATEGORY_CHOICES, 
        default='core'
    )
    description = models.TextField(
        blank=True
    )
    
    class Meta:
        ordering = ['category', 'name']
    
    def __str__(self):
        """Return the subject name."""
        return self.name


class ClassSubject(models.Model):
    """
    Junction model for classes and subjects with teacher assignment.
    
    This model represents which teacher teaches which subject in which class.
    It allows for multiple teachers per class (different subjects) and
    multiple classes per teacher.
    
    Attributes:
        school_class (ForeignKey): The class being taught
        subject (ForeignKey): The subject being taught
        teacher (ForeignKey): The teacher teaching this subject
        hours_per_week (int): Number of hours allocated weekly
    """
    
    school_class = models.ForeignKey(
        SchoolClass, 
        on_delete=models.CASCADE, 
        related_name='class_subjects'
    )
    subject = models.ForeignKey(
        Subject, 
        on_delete=models.CASCADE, 
        related_name='class_subjects'
    )
    teacher = models.ForeignKey(
        'staff.Staff', 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        related_name='taught_subjects',
        limit_choices_to={'role__in': ['teacher', 'class_teacher', 'subject_teacher']}
    )
    hours_per_week = models.PositiveIntegerField(
        default=2
    )
    
    class Meta:
        unique_together = ['school_class', 'subject']
        verbose_name = "Class Subject"
        verbose_name_plural = "Class Subjects"
    
    def __str__(self):
        """Return string representation of the assignment."""
        return f"{self.school_class} - {self.subject}"


class Attendance(models.Model):
    """
    Records student attendance for a specific class and date.
    
    This model tracks daily attendance for each student, including status
    (present, absent, late, etc.) and which teacher marked the attendance.
    
    Attributes:
        student (ForeignKey): The student being marked
        date (date): Date of attendance
        school_class (ForeignKey): The class session
        status (str): Attendance status from STATUS_CHOICES
        period (str): Time period (morning, afternoon, full day)
        marked_by (ForeignKey): Teacher who marked attendance
        remarks (str): Additional notes about the attendance
        device_id (str): Device identifier for offline sync
        synced (bool): Whether record is synced with server
        synced_at (datetime): When the record was last synced
    """
    
    STATUS_CHOICES = [
        ('present', 'Present'),
        ('absent', 'Absent'),
        ('late', 'Late'),
        ('excused', 'Excused Absence'),
        ('sick', 'Sick'),
        ('holiday', 'Holiday'),
    ]
    
    PERIOD_CHOICES = [
        ('morning', 'Morning'),
        ('afternoon', 'Afternoon'),
        ('full_day', 'Full Day'),
    ]
    
    student = models.ForeignKey(
        'students.Student', 
        on_delete=models.CASCADE, 
        related_name='attendances'
    )
    date = models.DateField(
        default=timezone.now
    )
    school_class = models.ForeignKey(
        SchoolClass, 
        on_delete=models.CASCADE, 
        related_name='attendances'
    )
    status = models.CharField(
        max_length=20, 
        choices=STATUS_CHOICES, 
        default='present'
    )
    period = models.CharField(
        max_length=10, 
        choices=PERIOD_CHOICES, 
        default='full_day'
    )
    
    # Teacher tracking
    marked_by = models.ForeignKey(
        'staff.Staff', 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        related_name='attendance_marked'
    )
    remarks = models.CharField(
        max_length=200, 
        blank=True
    )
    
    # For offline sync
    device_id = models.CharField(
        max_length=255, 
        blank=True
    )
    synced = models.BooleanField(
        default=False
    )
    synced_at = models.DateTimeField(
        null=True, 
        blank=True
    )
    
    class Meta:
        unique_together = ['student', 'date', 'period']
        ordering = ['-date', 'student__first_name']
        indexes = [
            models.Index(fields=['date']),
            models.Index(fields=['student', 'date']),
            models.Index(fields=['school_class', 'date']),
        ]
    
    def __str__(self):
        """Return string representation of the attendance record."""
        return f"{self.student} - {self.date} - {self.get_status_display()}"
        

# ---------- ADD TO BOTTOM OF academics/models.py ----------
from academics.models_grades import (   # noqa: F401, E402
    AcademicTerm,
    ReportSubject,
    MonthlyMark,
    TermSynthesis,
    ReportCard,
)
