from departments.models import Department
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.text import slugify
from django.utils import timezone
from datetime import date
from organization.models import BaseTenantModel

# Import foreign key models
from days.models import Day
from batch.models import Batch # Assuming Batch model exists in batch app
from batch_year.models import BatchYear
from semester.models import Semester
from course.models import Course # Assuming Course model exists in coures app
from teacher_management.models import Teacher # Assuming Teacher model exists in teacher_management app
from classroom.models import Classroom # Assuming Classroom model exists in classroom app
from timeslot.models import TimeSlot
from status.models import Status
from organization.models import BaseOrganizationModel



def get_draft_status():
    try:
        return Status.objects.get(slug='draft-routine').id
    except Status.DoesNotExist:
        return None

class Routine(BaseOrganizationModel):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255)
    department = models.ForeignKey(Department, on_delete=models.CASCADE, related_name='routines')
    batch = models.ForeignKey(Batch, on_delete=models.CASCADE, related_name='routines')
    year = models.ForeignKey(BatchYear, on_delete=models.CASCADE, related_name='routines')
    semester = models.ForeignKey(Semester, on_delete=models.CASCADE, related_name='routines')
    routine_year = models.IntegerField(null=True, blank=True)
    effective_from = models.DateField(null=True, blank=True)
    status = models.ForeignKey(Status, on_delete=models.SET_NULL, null=True, blank=True, limit_choices_to={'type': 'routine'}, default=get_draft_status)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = "Routine"
        verbose_name_plural = "Routines"
        constraints = [
            models.UniqueConstraint(fields=['organization', 'name'], name='unique_routine_name_per_org'),
            models.UniqueConstraint(fields=['organization', 'slug'], name='unique_routine_slug_per_org'),
        ]

    def save(self, *args, **kwargs):
        # If this routine is being published
        if self.status and self.status.slug == 'published-routine':
            try:
                # Get the status objects first to avoid joins in the filter
                published_status = Status.objects.get(slug='published-routine')
                archived_status = Status.objects.get(slug='archived-routine')

                # Find other published routines with the same criteria and demote them
                Routine.objects.filter(
                    batch=self.batch,
                    semester=self.semester,
                    year=self.year,
                    department=self.department,
                    status=published_status
                ).exclude(pk=self.pk).update(status=archived_status)

            except Status.DoesNotExist:
                # This is a critical failure if the required statuses are not in the DB.
                # Consider logging this event or raising an ImproperlyConfigured error.
                pass

        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)

    def __str__(self):
        return f"{self.name} - {self.batch} - {self.semester} - {self.year}"
    
def get_available_status():
    try:
        return Status.objects.get(slug='available-routine_data').id
    except Status.DoesNotExist:
        return None

class RoutineData(BaseOrganizationModel):
    id = models.AutoField(primary_key=True)
    routine = models.ForeignKey(Routine, on_delete=models.CASCADE, related_name='routine_data')
    day_of_week = models.ForeignKey(Day, on_delete=models.CASCADE, related_name='routines')
    course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='routine_entries')
    teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE, related_name='routine_entries')
    room = models.ForeignKey(Classroom, on_delete=models.SET_NULL, null=True, blank=True, related_name='routine_entries')
    time_slot = models.ForeignKey(TimeSlot, on_delete=models.CASCADE, related_name='routine_entries')
    status = models.ForeignKey(Status, on_delete=models.CASCADE, default=get_available_status, limit_choices_to={'type': 'routine_data'})
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    slot_count = models.IntegerField(default=1, verbose_name="Number of Slots")
    
    class Meta:
        db_table = 'routine_data'
        ordering = ['routine', 'time_slot']
        unique_together = ('routine', 'day_of_week', 'time_slot', 'room')
        verbose_name = "Routine Data"
        verbose_name_plural = "Routine Data"
        indexes = [
            models.Index(fields=['teacher', 'time_slot', 'day_of_week']),
        ]

    def clean(self):
        super().clean()
        if self.room:
            conflicting_slots = RoutineData.objects.filter(
                organization=self.organization,
                day_of_week=self.day_of_week,
                time_slot=self.time_slot,
                room=self.room
            ).exclude(routine__status__slug='archived-routine')
            
            if self.pk:
                conflicting_slots = conflicting_slots.exclude(pk=self.pk)
            
            if conflicting_slots.exists():
                conflict = conflicting_slots.first()
                raise ValidationError(
                    f"Room {self.room} is already occupied in routine '{conflict.routine.name}' "
                    f"for this day and time slot."
                )

    def save(self, *args, **kwargs):
        self.full_clean()
        super().save(*args, **kwargs)

    def __str__(self):
        return f"{self.routine.name} - {self.time_slot} - {self.course}"
