import logging
from datetime import timedelta

from django.db import transaction
from django.db.models import F
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from django.utils import timezone

from .models import Hotel, HotelBooking, RoomType, RoomTypeAvailability
from .services import generate_room_availability
from .tasks import sync_booking_to_pms_task, send_hotel_bill_email_task


logger = logging.getLogger(__name__)




# --- RoomType Signals ---

@receiver(pre_save, sender=RoomType)
def capture_old_total_rooms(sender, instance, **kwargs):
    """
    Capture the previous total_rooms of the RoomType before saving.
    """
    if instance.pk:
        try:
            old_instance = RoomType.objects.get(pk=instance.pk)
            instance._old_total_rooms = old_instance.total_rooms
        except RoomType.DoesNotExist:
            instance._old_total_rooms = None
    else:
        instance._old_total_rooms = None

@receiver(post_save, sender=RoomType)
def create_availability(sender, instance, created, **kwargs):
    """
    Generate room availability when a new RoomType is created, 
    and update availability when total_rooms is changed.
    """
    if created:
        generate_room_availability(instance)
    else:
        old_total = getattr(instance, '_old_total_rooms', None)
        if old_total is not None and old_total != instance.total_rooms:
            delta = instance.total_rooms - old_total
            RoomTypeAvailability.objects.filter(
                room_type=instance,
                date__gte=timezone.now().date()
            ).update(available_rooms=F('available_rooms') + delta)


# --- HotelBooking Signals ---

@receiver(pre_save, sender=HotelBooking)
def capture_old_status(sender, instance, **kwargs):
    """
    Capture the previous status of the booking before saving.
    Used to detect status changes in post_save signals.
    """
    if instance.pk:
        try:
            old_instance = HotelBooking.objects.get(pk=instance.pk)
            instance._old_status = old_instance.status
        except HotelBooking.DoesNotExist:
            instance._old_status = None
    else:
        instance._old_status = None


@receiver(post_save, sender=HotelBooking)
def sync_booking_to_pms(sender, instance, created, **kwargs):
    """
    Trigger PMS synchronization when a booking is created or becomes confirmed.
    """
    should_sync = False




    
    should_send_bill = False

    if created:
        if instance.status == 'confirmed':
           should_sync = True
           logger.info(f"New confirmed booking {instance.id} created. Syncing to PMS.")
        elif instance.status == 'completed':
           should_send_bill = True
           logger.info(f"New completed booking {instance.id} created. Sending bill.")
        elif instance.status == 'pending':
           logger.info(f"New pending booking {instance.id} created. Waiting for confirmation.")
    else:
        # Update
        old_status = getattr(instance, '_old_status', None)
        if old_status != 'confirmed' and instance.status == 'confirmed':
            should_sync = True
            logger.info(f"Booking {instance.id} status changed to confirmed. Syncing to PMS.")
        if old_status != 'completed' and instance.status == 'completed':
            should_send_bill = True
            logger.info(f"Booking {instance.id} status changed to completed. Sending bill email.")

    if should_sync:
        def trigger_sync():
            try:
                sync_booking_to_pms_task.delay(instance.id)
            except Exception as e:
                logger.error(f"Error scheduling PMS sync for booking {instance.id}: {str(e)}")
                
        # Offload to Celery in production
        transaction.on_commit(trigger_sync)

    if should_send_bill:
        def trigger_email_and_whatsapp():
            import threading
            from .tasks import send_hotel_bill_email_task, send_hotel_bill_whatsapp_task
            try:
                t1 = threading.Thread(target=send_hotel_bill_email_task, args=(instance.id,))
                t1.start()
                t2 = threading.Thread(target=send_hotel_bill_whatsapp_task, args=(instance.id,))
                t2.start()
            except Exception as e:
                logger.error(f"Error scheduling hotel bill notifications for booking {instance.id}: {str(e)}")
        transaction.on_commit(trigger_email_and_whatsapp)




# --- Hotel Signals (Real-time Connection Settings Mapping) ---

@receiver(post_save, sender=Hotel)
def trigger_connection_mapping_sync(sender, instance, created, **kwargs):
    """
    Real-time connection settings mapping hook.
    When a Hotel is created or updated in HotelFinder (OTA), if pms_sync_url 
    and pms_sync_token are set, automatically POST the mapping credentials 
    to AAthitya PMS to create or update the ChannelConnection.
    """
    if not instance.pms_sync_url:
        return
        
    def run_mapping_sync():
        import requests
        from urllib.parse import urlparse
        from django.conf import settings
        
        try:
            # Parse PMS base URL and branch_id
            url = instance.pms_sync_url
            parsed = urlparse(url)
            base_url = f"{parsed.scheme}://{parsed.netloc}"
            mapping_endpoint = f"{base_url}/channel-manager/api/v1/hotelfinder/connection-mapping/"
            
            # Determine branch ID
            branch_id = instance.pms_branch_id
            if not branch_id:
                parts = [p for p in url.strip('/').split('/') if p]
                for part in reversed(parts):
                    if part.isdigit():
                        branch_id = int(part)
                        break
            
            if not branch_id:
                logger.error(f"[Connection Mapping Sync] Could not extract branch_id from URL: {url}")
                return
                
            # Construct payload
            hotelfinder_url = getattr(settings, 'HOTELFINDER_URL', 'http://localhost:8000')
            
            payload = {
                "property_id": instance.id,
                "property_name": instance.name,
                "branch_id": branch_id,
                "api_key": instance.pms_sync_token or '',
                "hotelfinder_url": hotelfinder_url,
                "status": "ACTIVE" if instance.is_active else "DISABLED"
            }
            
            headers = {
                "Content-Type": "application/json"
            }
            
            logger.info(f"[Connection Mapping Sync] Sending connection mapping for hotel {instance.id} to {mapping_endpoint}")
            response = requests.post(mapping_endpoint, json=payload, headers=headers, timeout=10)
            
            if response.status_code == 200:
                logger.info(f"[Connection Mapping Sync] Successfully mapped hotel {instance.id}. Response: {response.text}")
            else:
                logger.error(f"[Connection Mapping Sync] PMS returned status {response.status_code}. Response: {response.text}")
                
        except Exception as e:
            logger.error(f"[Connection Mapping Sync] Failed to sync connection mapping for hotel {instance.id}: {str(e)}")
            
    # Run after transaction commits to ensure DB state is flushed
    transaction.on_commit(run_mapping_sync)


