from django.db import models
from django.core.exceptions import ValidationError
from utils.services import make_timezone_aware, current_date
from utils.validators import  validate_image

class Tenant(models.Model):
    avatar = models.ImageField(
        upload_to='tenant_avatars/',
        blank=True,
        null=True,
        validators=[validate_image]
    )

    name = models.CharField(max_length=255)
    email = models.EmailField(unique=True)
    phone_number = models.CharField(max_length=10, unique=True)
    adhar_number = models.CharField(max_length=12, unique=True)

    id_proof = models.FileField(
        upload_to='tenant_id_proofs/',
        blank=True,
        null=True,
    )

    check_in = models.DateTimeField()
    check_out = models.DateTimeField(null=True, blank=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    terms_and_conditions = models.BooleanField(default=False) # type: ignore

    def __str__(self):
        return f"{self.name} - {self.phone_number}"

    def clean(self):
        if self.check_in:
            self.check_in = current_date(self.check_in)

        # Validate file size for avatar
        if self.avatar and self.avatar.size > 2 * 1024 * 1024:  # type: ignore
            raise ValidationError({'avatar': 'Avatar file size must not exceed 2MB.'})

        # Validate file size for ID proof
        if self.id_proof and self.id_proof.size > 5 * 1024 * 1024: # type: ignore
            raise ValidationError({'id_proof': 'ID proof file size must not exceed 5MB.'})

        # Ensure check-out is greater than check-in
        if self.check_out and self.check_out <= self.check_in:
            raise ValidationError({'check_out': "Check-out date must be later than check-in date."})

        # Ensure terms and conditions are accepted
        if not self.pk and not self.terms_and_conditions:
            raise ValidationError({'terms_and_conditions': 'Terms and conditions must be accepted.'})
    @property
    def current_room(self):
        return self.rooms.filter(is_active=True).first() # type: ignore

    @property
    def last_room(self):
        """Returns the most recent room (even if tenant has left)"""
        return self.rooms.order_by('-joined_on').first() # type: ignore

    @property
    def total_stay(self):
        """Returns the total number of days the tenant has stayed"""
        tenant_rooms = self.rooms.all() # type: ignore
        if tenant_rooms.exists():
            sum = 0
            for room in tenant_rooms:
                sum += room.total_stay
            return sum
        return 0

    class Meta:
        ordering = ['name']
        db_table = 'tenants'


class Guardian(models.Model):
    tenant = models.OneToOneField(Tenant, on_delete=models.CASCADE, related_name='guardian')
    name = models.CharField(max_length=255)
    phone_number = models.CharField(max_length=10)
    relation = models.CharField(max_length=50)

    def __str__(self):
        return f"{self.name} ({self.relation})"

    class Meta:
        db_table = 'guardians'


class Occupation(models.Model):
    tenant = models.OneToOneField(Tenant, on_delete=models.CASCADE, related_name='occupation')
    type = models.CharField(
        max_length=20,
        choices=[('job', 'Job'), ('student', 'Student'), ('other', 'Other')]
    )
    institute_name = models.TextField(max_length=255)
    address = models.CharField(max_length=255)
    contact = models.CharField(max_length=10)

    def __str__(self):
        return f"{self.get_type_display()} - {self.institute_name} - {self.address}" # type: ignore

    class Meta:
        db_table = 'occupations'

class TenantRent(models.Model):
    tenant = models.OneToOneField(Tenant, on_delete=models.CASCADE, related_name='rent_details')
    security_amount = models.DecimalField(max_digits=10, decimal_places=2, help_text="Security deposit amount")
    rent_due = models.DateTimeField(help_text="Next rent due date")
    meal = models.ForeignKey('meal.Meal', on_delete=models.SET_NULL, null=True, blank=True, related_name='tenant_meals')
    food_due = models.DateTimeField(help_text="Next food due date")

    def __str__(self):
        return f"Rent details for {self.tenant.name}"

    # def clean(self):
    #     print("see this", self.meal, self.tenant)


    class Meta:
        db_table = 'tenant_rent'

class TenantRoom(models.Model):
    tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='rooms')
    room = models.ForeignKey('room.Room', on_delete=models.PROTECT, null=True, blank=True, related_name='tenant_rooms')
    joined_on = models.DateTimeField(help_text="Join date")
    left_on = models.DateTimeField(null=True, blank=True)
    is_single_sharing = models.BooleanField(default=False) # type: ignore | This helps tracking if the room was opted for single sharing
    is_active = models.BooleanField(default=True)  # type: ignore | Add this to track current room
    notes = models.TextField(blank=True, null=True)  # Optional: for tracking reason for room change

    @property
    def total_stay(self):
        """Returns the total number of days the tenant has stayed"""
        return (make_timezone_aware(self.left_on if self.left_on else current_date()) - make_timezone_aware(self.joined_on)).days + 1 # type: ignore

    def clean(self):
        # Validate that left_on is after joined_on
        if self.left_on and self.left_on <= self.joined_on:
            raise ValidationError({'left_on': "Left date must be after join date"})

        # Validate overlapping periods for same tenant
        overlapping = TenantRoom.objects.filter( # type: ignore
            tenant=self.tenant,
            joined_on__lte=self.left_on or '9999-12-31',
            left_on__gte=self.joined_on
        ).exclude(pk=self.pk)
        if overlapping.exists():
            raise ValidationError("This tenant already has a room assigned during this period")

    def save(self, *args, **kwargs):
        if self.left_on:
            self.is_active = False
        super().save(*args, **kwargs)

    def __str__(self):
        return f"Room details for {self.tenant.name}"

    class Meta:
        db_table = 'tenant_room'
        ordering = ['-joined_on']
        unique_together = ('tenant', 'room', 'joined_on')
        constraints = [
            models.CheckConstraint(
                check=models.Q(left_on__gt=models.F('joined_on')) | models.Q(left_on__isnull=True),
                    name='valid_date_range'
                )
            ]
