import logging

from asgiref.sync import async_to_sync

from django.db.models.signals import post_save, post_delete, pre_delete
from django.dispatch import receiver
from channels.layers import get_channel_layer
from events.models import RSVP, Activity, Event, ActivitySelection, Guest, Response

logger = logging.getLogger(__name__)


###
# Guests
###

@receiver(post_delete, sender=Guest)
def guest_deleted(sender, instance, **kwargs):
    """Delete question responses for this guest"""
    guest:Guest = instance
    
    logger.debug(f"Signal {guest}")
    
    guest_delete_responses(guest)
    guest_notify_activities(guest)

def guest_delete_responses(guest:Guest):
    # Remove all responses from the guest that is deleted
    Response.objects.filter(guest=guest).delete()

def guest_notify_activities(guest:Guest):
    """Broadcast activity selection changes to all connected clients."""
    rsvp:RSVP = guest.rsvp
    event:Event = rsvp.event
    
    # Get all activities with this RSVP
    activities = rsvp.activities
    
    for activity in activities.all():
        logger.debug(f"Signal {activity}")
        
        capacity = activity.remaining_capacity()
        if capacity is None:
            capacity = 100
        
        activity_json = {
            "activity": str(activity.id),
            "rsvp": str(rsvp.id),
            "action": "select",
            "attendees": activity.attendee_count(),
            "capacity": capacity,
            "guests": activity.attendee_list()
        }
        
        # Send message to the group
        async_to_sync(send_channel)(event.id, activity_json)

@receiver(post_save, sender=Guest)
def activity_guests_changed(sender, instance, created, **kwargs):
    """Broadcast activity selection changes to all connected clients."""
    guest:Guest = instance
    rsvp:RSVP = guest.rsvp
    event:Event = rsvp.event
    
    logger.debug(f"Guest added: {guest.name}")
    
    # Get all activities with this RSVP
    activities = rsvp.activities
    
    for activity in activities.all():
        logger.debug(f"Signal {activity}")
        
        capacity = activity.remaining_capacity()
        if capacity is None:
            capacity = 100
        
        activity_json = {
            "activity": str(activity.id),
            "rsvp": str(rsvp.id),
            "action": "select",
            "attendees": activity.attendee_count(),
            "capacity": capacity,
            "guests": activity.attendee_list()
        }
        
        # Send message to the group
        async_to_sync(send_channel)(event.id, activity_json)

###
# Activity Selections
###

@receiver(post_save, sender=ActivitySelection)
def activity_selection_changed(sender, instance, created, **kwargs):
    """Broadcast activity selection changes to all connected clients."""
    activity:Activity = instance.activity
    rsvp:RSVP = instance.rsvp
    event:Event = activity.event
    
    logger.debug(f"Signal {activity}")
    
    capacity = activity.remaining_capacity()
    if capacity is None:
        capacity = 100
    
    activity_json = {
        "activity": str(activity.id),
        "rsvp": str(rsvp.id),
        "action": "select",
        "attendees": activity.attendee_count(),
        "capacity": capacity,
        "guests": activity.attendee_list()
    }
    
    # Send message to the group
    async_to_sync(send_channel)(event.id, activity_json)

@receiver(post_delete, sender=ActivitySelection)
def activity_selection_deleted(sender, instance, **kwargs):
    """Broadcast activity selection changes to all connected clients."""
    activity:Activity = instance.activity
    rsvp:RSVP = instance.rsvp
    event:Event = activity.event
    
    logger.debug(f"Signal {activity}")
    
    capacity = activity.remaining_capacity()
    if capacity is None:
        capacity = 100
    
    activity_json = {
        "activity": str(activity.id),
        "rsvp": str(rsvp.id),
        "action": "remove",
        "attendees": activity.attendee_count(),
        "capacity": capacity,
        "guests": activity.attendee_list()
    }
    
    # Send message to the group
    async_to_sync(send_channel)(event.id, activity_json)


async def send_channel(event_id, activity_json):
   
    channel_layer = get_channel_layer()
    if channel_layer:
        await channel_layer.group_send(
                f"activity_{event_id}",
                {
                    "type": "group.message",
                    "activity_json": activity_json
                }
            )