from django.db import models
from django.conf import settings
from django.core.exceptions import ValidationError
from datetime import timedelta


User = settings.AUTH_USER_MODEL


class Hotel(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="hotels")
    pms_id = models.IntegerField(null=True, blank=True, unique=True, help_text="ID from the PMS")
    pms_hotel_id = models.IntegerField(null=True, blank=True, help_text="PMS Hotel ID (for filtering list APIs)")
    pms_branch_id = models.IntegerField(null=True, blank=True, help_text="PMS Branch ID (for filtering list APIs)")
    pms_sync_url = models.URLField(blank=True, null=True, help_text="PMS API URL to fetch details from (e.g., https://.../hotels/1/)")
    pms_sync_token = models.CharField(max_length=255, blank=True, null=True, help_text="Token or Key for PMS API")
    name = models.CharField(max_length=200)
    phone = models.CharField(max_length=100, blank=True, null=True, help_text="Contact Numbers")
    email = models.EmailField(blank=True, null=True, help_text="Hotel Email")
    branch = models.CharField(max_length=100, default="Main")
    city = models.CharField(max_length=100)
    address = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
    longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
    rating = models.FloatField(default=0.0)
    amenities = models.TextField(blank=True)
    state = models.CharField(max_length=100, blank=True, null=True)
    country = models.CharField(max_length=100, default="India")
    images = models.ImageField(upload_to="hotel_images/", blank=True, null=True)
    gstin = models.CharField(max_length=20, blank=True, null=True)
    pan = models.CharField(max_length=20, blank=True, null=True)
    checkin_time = models.TimeField(default="14:00")
    checkout_time = models.TimeField(default="11:00")
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name


class RoomType(models.Model):
    hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name="room_types")
    pms_id = models.IntegerField(null=True, blank=True, unique=True, help_text="ID from the PMS")
    name = models.CharField(max_length=100)
    branch = models.CharField(max_length=100, default="Main")
    price = models.DecimalField(max_digits=10, decimal_places=2)
    weekend_price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, help_text="Specific price for Weekends (Sat/Sun)")
    demand_trigger_occupancy = models.FloatField(default=80.0, help_text="Occupancy % to trigger demand pricing")
    demand_price_multiplier = models.DecimalField(max_digits=4, decimal_places=2, default=1.00, help_text="Multiplier when demand threshold is met")
    total_rooms = models.PositiveIntegerField()

    def get_price_for_date(self, date):
        from decimal import Decimal
        # 1. Seasonal Pricing
        season = self.seasonal_prices.filter(start_date__lte=date, end_date__gte=date).first()
        if season:
            base_price = season.price
        # 2. Weekend Pricing (Saturday=5, Sunday=6)
        elif date.weekday() in [5, 6] and self.weekend_price is not None:
            base_price = self.weekend_price
        else:
            base_price = self.price

        # 3. Demand-based pricing
        try:
            availability = self.availability.get(date=date)
            if self.total_rooms > 0:
                occupancy = ((self.total_rooms - availability.available_rooms) / self.total_rooms) * 100
                if occupancy >= self.demand_trigger_occupancy:
                    return base_price * self.demand_price_multiplier
        except self.availability.model.DoesNotExist:
            pass

        return base_price

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


class RoomTypeImage(models.Model):
    room_type = models.ForeignKey(RoomType, on_delete=models.CASCADE, related_name="images")
    image = models.ImageField(upload_to="room_type_images/")
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Image for {self.room_type.name}"


class RoomTypeAvailability(models.Model):
    room_type = models.ForeignKey(RoomType, on_delete=models.CASCADE, related_name="availability")
    date = models.DateField()
    available_rooms = models.PositiveIntegerField()

    class Meta:
        unique_together = ("room_type", "date")
        ordering = ["date"]

    def __str__(self):
        return f"{self.room_type} | {self.date}"


class SeasonalPricing(models.Model):
    room_type = models.ForeignKey(RoomType, on_delete=models.CASCADE, related_name="seasonal_prices")
    start_date = models.DateField()
    end_date = models.DateField()
    price = models.DecimalField(max_digits=10, decimal_places=2)

    class Meta:
        ordering = ["start_date"]

    def __str__(self):
        return f"{self.room_type} | {self.start_date} to {self.end_date} - {self.price}"


class HotelBooking(models.Model):
    STATUS_CHOICES = (
        ("pending", "Pending"),
        ("confirmed", "Confirmed"),
        ("completed", "Completed"),
        ("cancelled", "Cancelled"),
    )

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="hotel_bookings")
    hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE)
    branch = models.CharField(max_length=100)
    room_type = models.ForeignKey(RoomType, on_delete=models.CASCADE)

    check_in = models.DateField()
    check_out = models.DateField()
    rooms_booked = models.PositiveIntegerField()

    guest_name = models.CharField(max_length=100, blank=True, null=True)
    email = models.EmailField(blank=True, null=True)
    mobile = models.CharField(max_length=15, blank=True, null=True)
    gst_no = models.CharField(max_length=20, blank=True, null=True)

    invoice_number = models.CharField(max_length=50, blank=True, null=True, unique=True)
    invoice_date = models.DateField(blank=True, null=True)

    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    @property
    def total_amount(self):
        total_price = 0
        current_date = self.check_in
        while current_date < self.check_out:
            day_price = self.room_type.get_price_for_date(current_date)
            total_price += day_price
            current_date += timedelta(days=1)
        return total_price * self.rooms_booked

    @property
    def nights(self):
        return (self.check_out - self.check_in).days

    def __str__(self):
        return f"{self.user} - {self.hotel}"

    def clean(self):
        if not all([self.check_in, self.check_out, self.room_type, self.rooms_booked]):
            return

        current_date = self.check_in
        while current_date < self.check_out:
            try:
                availability = RoomTypeAvailability.objects.get(
                    room_type=self.room_type,
                    date=current_date
                )
                if self.rooms_booked > availability.available_rooms:
                    raise ValidationError(f"Not enough rooms available on {current_date}. Available: {availability.available_rooms}")
            except RoomTypeAvailability.DoesNotExist:
                raise ValidationError(f"No availability record found for {current_date}")
            
            current_date += timedelta(days=1)
