# -*- coding: utf-8 -*-
"""
Channel Management Signals

This module contains signal handlers for channel-related operations including
automated logging, cache invalidation, and background task triggering.
"""

import logging
from django.db.models.signals import post_save, post_delete, pre_save
from django.dispatch import receiver
from django.utils import timezone
from django.core.cache import cache
from django.contrib.contenttypes.models import ContentType

from .models import (
    Channel, ChannelZone, ChannelCodec, ChannelZoneRelation,
    EPGProgram, Jingle, JingleDetection, ChannelSchedule
)
from apps.activities.helpers import log_user_activity

logger = logging.getLogger(__name__)


# ============================================================================
# Channel Signals
# ============================================================================

@receiver(post_save, sender=Channel)
def channel_post_save(sender, instance, created, **kwargs):
    """
    Handle post-save operations for Channel model.
    
    Args:
        sender: The model class (Channel)
        instance: The actual instance being saved
        created: Boolean indicating if this is a new instance
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear channel-related cache
        cache_keys = [
            f'channel_{instance.id}',
            f'channel_list',
            f'active_channels',
            f'channel_stats',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        action = 'created' if created else 'updated'
        logger.info(f"Channel {instance.name} ({instance.id}) was {action}")
        
        # Trigger health check for new channels
        if created:
            from .tasks import perform_channel_health_check
            perform_channel_health_check.delay(instance.id)
            
        # Update channel statistics
        from .tasks import update_channel_statistics
        update_channel_statistics.delay(instance.id)
        
    except Exception as e:
        logger.error(f"Error in channel_post_save signal: {e}")


@receiver(post_delete, sender=Channel)
def channel_post_delete(sender, instance, **kwargs):
    """
    Handle post-delete operations for Channel model.
    
    Args:
        sender: The model class (Channel)
        instance: The actual instance being deleted
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear channel-related cache
        cache_keys = [
            f'channel_{instance.id}',
            f'channel_list',
            f'active_channels',
            f'channel_stats',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        logger.info(f"Channel {instance.name} ({instance.id}) was deleted")
        
        # Clean up related files if they exist
        if instance.logo:
            try:
                instance.logo.delete(save=False)
            except Exception as e:
                logger.warning(f"Could not delete logo file for channel {instance.id}: {e}")
                
    except Exception as e:
        logger.error(f"Error in channel_post_delete signal: {e}")


@receiver(pre_save, sender=Channel)
def channel_pre_save(sender, instance, **kwargs):
    """
    Handle pre-save operations for Channel model.
    
    Args:
        sender: The model class (Channel)
        instance: The actual instance being saved
        **kwargs: Additional keyword arguments
    """
    try:
        # Update last_health_check if status changed to active
        if instance.pk:
            try:
                old_instance = Channel.objects.get(pk=instance.pk)
                if (old_instance.status != 'active' and 
                    instance.status == 'active'):
                    instance.last_health_check = timezone.now()
            except Channel.DoesNotExist:
                pass
                
    except Exception as e:
        logger.error(f"Error in channel_pre_save signal: {e}")


# ============================================================================
# Channel Zone Signals
# ============================================================================

@receiver(post_save, sender=ChannelZone)
def channel_zone_post_save(sender, instance, created, **kwargs):
    """
    Handle post-save operations for ChannelZone model.
    
    Args:
        sender: The model class (ChannelZone)
        instance: The actual instance being saved
        created: Boolean indicating if this is a new instance
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear zone-related cache
        cache_keys = [
            f'zone_{instance.id}',
            f'zone_list',
            f'active_zones',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        action = 'created' if created else 'updated'
        logger.info(f"Channel Zone {instance.name} ({instance.id}) was {action}")
        
    except Exception as e:
        logger.error(f"Error in channel_zone_post_save signal: {e}")


@receiver(post_delete, sender=ChannelZone)
def channel_zone_post_delete(sender, instance, **kwargs):
    """
    Handle post-delete operations for ChannelZone model.
    
    Args:
        sender: The model class (ChannelZone)
        instance: The actual instance being deleted
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear zone-related cache
        cache_keys = [
            f'zone_{instance.id}',
            f'zone_list',
            f'active_zones',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        logger.info(f"Channel Zone {instance.name} ({instance.id}) was deleted")
        
    except Exception as e:
        logger.error(f"Error in channel_zone_post_delete signal: {e}")


# ============================================================================
# EPG Program Signals
# ============================================================================

@receiver(post_save, sender=EPGProgram)
def epg_program_post_save(sender, instance, created, **kwargs):
    """
    Handle post-save operations for EPGProgram model.
    
    Args:
        sender: The model class (EPGProgram)
        instance: The actual instance being saved
        created: Boolean indicating if this is a new instance
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear EPG-related cache
        cache_keys = [
            f'epg_program_{instance.id}',
            f'channel_{instance.channel.id}_programs',
            f'epg_current_programs',
            f'epg_upcoming_programs',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        action = 'created' if created else 'updated'
        logger.info(f"EPG Program {instance.title} ({instance.id}) was {action}")
        
        # Schedule ad insertion tasks if program has ad breaks
        if instance.has_ad_breaks and instance.ad_break_positions:
            from .tasks import schedule_ad_insertion
            schedule_ad_insertion.delay(instance.id)
            
    except Exception as e:
        logger.error(f"Error in epg_program_post_save signal: {e}")


@receiver(post_delete, sender=EPGProgram)
def epg_program_post_delete(sender, instance, **kwargs):
    """
    Handle post-delete operations for EPGProgram model.
    
    Args:
        sender: The model class (EPGProgram)
        instance: The actual instance being deleted
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear EPG-related cache
        cache_keys = [
            f'epg_program_{instance.id}',
            f'channel_{instance.channel.id}_programs',
            f'epg_current_programs',
            f'epg_upcoming_programs',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        logger.info(f"EPG Program {instance.title} ({instance.id}) was deleted")
        
    except Exception as e:
        logger.error(f"Error in epg_program_post_delete signal: {e}")


# ============================================================================
# Jingle Signals
# ============================================================================

@receiver(post_save, sender=Jingle)
def jingle_post_save(sender, instance, created, **kwargs):
    """
    Handle post-save operations for Jingle model.
    
    Args:
        sender: The model class (Jingle)
        instance: The actual instance being saved
        created: Boolean indicating if this is a new instance
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear jingle-related cache
        cache_keys = [
            f'jingle_{instance.id}',
            f'channel_{instance.channel.id}_jingles',
            f'active_jingles',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        action = 'created' if created else 'updated'
        logger.info(f"Jingle {instance.name} ({instance.id}) was {action}")
        
        # Generate audio fingerprint for new jingles
        if created and instance.file:
            from .tasks import generate_jingle_fingerprint
            generate_jingle_fingerprint.delay(instance.id)
            
    except Exception as e:
        logger.error(f"Error in jingle_post_save signal: {e}")


@receiver(post_delete, sender=Jingle)
def jingle_post_delete(sender, instance, **kwargs):
    """
    Handle post-delete operations for Jingle model.
    
    Args:
        sender: The model class (Jingle)
        instance: The actual instance being deleted
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear jingle-related cache
        cache_keys = [
            f'jingle_{instance.id}',
            f'channel_{instance.channel.id}_jingles',
            f'active_jingles',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        logger.info(f"Jingle {instance.name} ({instance.id}) was deleted")
        
        # Clean up jingle file
        if instance.file:
            try:
                instance.file.delete(save=False)
            except Exception as e:
                logger.warning(f"Could not delete jingle file for {instance.id}: {e}")
                
    except Exception as e:
        logger.error(f"Error in jingle_post_delete signal: {e}")


# ============================================================================
# Jingle Detection Signals
# ============================================================================

@receiver(post_save, sender=JingleDetection)
def jingle_detection_post_save(sender, instance, created, **kwargs):
    """
    Handle post-save operations for JingleDetection model.
    
    Args:
        sender: The model class (JingleDetection)
        instance: The actual instance being saved
        created: Boolean indicating if this is a new instance
        **kwargs: Additional keyword arguments
    """
    try:
        # Update jingle usage statistics
        if created:
            instance.jingle.mark_played()
            
        # Log high-confidence detections
        if instance.confidence_score >= 0.9:
            logger.info(
                f"High-confidence jingle detection: {instance.jingle.name} "
                f"on {instance.channel.name} (confidence: {instance.confidence_score})"
            )
            
        # Auto-confirm high-confidence detections
        if created and instance.confidence_score >= 0.95:
            instance.status = 'confirmed'
            instance.save(update_fields=['status'])
            
    except Exception as e:
        logger.error(f"Error in jingle_detection_post_save signal: {e}")


# ============================================================================
# Channel Schedule Signals
# ============================================================================

@receiver(post_save, sender=ChannelSchedule)
def channel_schedule_post_save(sender, instance, created, **kwargs):
    """
    Handle post-save operations for ChannelSchedule model.
    
    Args:
        sender: The model class (ChannelSchedule)
        instance: The actual instance being saved
        created: Boolean indicating if this is a new instance
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear schedule-related cache
        cache_keys = [
            f'schedule_{instance.id}',
            f'channel_{instance.channel.id}_schedules',
            f'active_schedules',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        action = 'created' if created else 'updated'
        logger.info(f"Channel Schedule {instance.title} ({instance.id}) was {action}")
        
        # Schedule notifications for special events
        if instance.schedule_type in ['special', 'emergency'] and created:
            from .tasks import send_schedule_notifications
            send_schedule_notifications.delay(instance.id)
            
    except Exception as e:
        logger.error(f"Error in channel_schedule_post_save signal: {e}")


# ============================================================================
# Channel Zone Relation Signals
# ============================================================================

@receiver(post_save, sender=ChannelZoneRelation)
def channel_zone_relation_post_save(sender, instance, created, **kwargs):
    """
    Handle post-save operations for ChannelZoneRelation model.
    
    Args:
        sender: The model class (ChannelZoneRelation)
        instance: The actual instance being saved
        created: Boolean indicating if this is a new instance
        **kwargs: Additional keyword arguments
    """
    try:
        # Clear relation-related cache
        cache_keys = [
            f'channel_{instance.channel.id}_zones',
            f'zone_{instance.zone.id}_channels',
            f'channel_zone_relations',
        ]
        cache.delete_many(cache_keys)
        
        # Log activity
        action = 'created' if created else 'updated'
        logger.info(
            f"Channel-Zone relation for {instance.channel.name} "
            f"in {instance.zone.name} was {action}"
        )
        
        # Test VPN connection for new relations with VPN
        if created and instance.vpn_type != 'none':
            from .tasks import test_vpn_connection
            test_vpn_connection.delay(instance.id)
            
    except Exception as e:
        logger.error(f"Error in channel_zone_relation_post_save signal: {e}")