from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from .models import Booking
import logging

logger = logging.getLogger(__name__)


@receiver(pre_save, sender=Booking)
def capture_old_booking_status(sender, instance, **kwargs):
    """Capture old status to trigger notifications exactly once on status change."""
    if instance.pk:
        try:
            old_instance = Booking.objects.get(pk=instance.pk)
            instance._old_status = old_instance.status
            instance._old_payment_status = old_instance.payment_status
        except Booking.DoesNotExist:
            instance._old_status = None
            instance._old_payment_status = None
    else:
        instance._old_status = None
        instance._old_payment_status = None


@receiver(post_save, sender=Booking)
def booking_completed_loyalty(sender, instance, created, **kwargs):
    """Fire the loyalty Rules Engine when a booking's payment reaches PAID status."""
    # Skip evaluation if the booking is just created but items haven't been added yet (total_amount = 0)
    if created and instance.total_amount == 0:
        return

    if instance.payment_status == 'PAID' and not instance.is_loyalty_evaluated:
        from .loyalty_services import RulesEngine
        try:
            RulesEngine.evaluate_booking(instance)
        except Exception:
            logger.exception("Loyalty rules engine failed for booking %d", instance.id)


@receiver(post_save, sender=Booking)
def send_restaurant_bill_on_completion(sender, instance, created, **kwargs):
    """Send email + WhatsApp bill when the booking status becomes COMPLETED."""
    should_send = False

    if created and instance.status == 'COMPLETED':
        should_send = True
    elif not created:
        old_status = getattr(instance, '_old_status', None)
        if old_status != 'COMPLETED' and instance.status == 'COMPLETED':
            should_send = True

    if should_send:
        from .tasks import send_restaurant_bill_email_task, send_restaurant_bill_whatsapp_task
        from django.db import transaction

        def trigger_bill_notifications():
            try:
                # Use Celery tasks if available, otherwise run synchronously
                # Since CELERY_TASK_ALWAYS_EAGER is True, this runs in-process anyway
                send_restaurant_bill_email_task(instance.id)
            except Exception as e:
                logger.error("Error sending bill email for booking %d: %s", instance.id, e)
            try:
                send_restaurant_bill_whatsapp_task(instance.id)
            except Exception as e:
                logger.error("Error sending bill WhatsApp for booking %d: %s", instance.id, e)

        transaction.on_commit(trigger_bill_notifications)


@receiver(post_save, sender=Booking)
def send_whatsapp_status_update(sender, instance, created, **kwargs):
    """
    Send WhatsApp notification to customer when order status changes.
    Only fires for WhatsApp orders (identified by order_notes containing 'WhatsApp').
    """
    if created:
        return  # The webhook already sends confirmation on creation

    old_status = getattr(instance, '_old_status', None)
    if old_status is None or old_status == instance.status:
        return  # No status change

    # Only send for WhatsApp-originated orders to avoid spamming non-WhatsApp customers
    is_whatsapp_order = 'whatsapp' in (instance.order_notes or '').lower()
    if not is_whatsapp_order:
        return

    from django.db import transaction

    def send_status_notification():
        try:
            from .whatsapp_service import send_order_status_update
            send_order_status_update(instance)
        except Exception as e:
            logger.error("WhatsApp status update failed for booking %d: %s", instance.id, e)

    transaction.on_commit(send_status_notification)

@receiver(post_save, sender=Booking)
def broadcast_payment_status(sender, instance, created, **kwargs):
    old_payment_status = getattr(instance, '_old_payment_status', None)
    if created or old_payment_status != instance.payment_status:
        from channels.layers import get_channel_layer
        from asgiref.sync import async_to_sync
        
        channel_layer = get_channel_layer()
        group_name = f'payment_status_{instance.id}'
        
        message_payload = {
            'type': 'payment_status_update',
            'payment_status': instance.payment_status,
            'booking_id': str(instance.id)
        }
        
        if channel_layer:
            async_to_sync(channel_layer.group_send)(
                group_name,
                message_payload
            )
            
        # Write to the local event_outbox to trigger zero-latency WebSocket broadcast
        from django.db import connection
        import json
        try:
            with connection.cursor() as cursor:
                engine = connection.settings_dict.get('ENGINE', '')
                if 'mysql' in engine:
                    cursor.execute("""
                        CREATE TABLE IF NOT EXISTS event_outbox (
                            id INT AUTO_INCREMENT PRIMARY KEY,
                            topic VARCHAR(255),
                            payload TEXT,
                            status VARCHAR(20) DEFAULT 'PENDING',
                            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                        )
                    """)
                else:
                    cursor.execute("""
                        CREATE TABLE IF NOT EXISTS event_outbox (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            topic VARCHAR(255),
                            payload TEXT,
                            status VARCHAR(20) DEFAULT 'PENDING',
                            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                        )
                    """)
                cursor.execute("""
                    INSERT INTO event_outbox (topic, payload)
                    VALUES (%s, %s)
                """, ['payment_status_update', json.dumps(message_payload)])
        except Exception as e:
            logger.error("Error writing to event_outbox for payment_status: %s", e)
