"""
Celery Tasks for Jingle Detection and Ad Break Processing

This module contains Celery tasks for handling jingle detection,
ad break analysis, and related background processing operations.
"""

import logging
from typing import Optional, Dict, Any, List
from celery import shared_task
from django.utils import timezone
from django.conf import settings

from apps.jingles.models import JingleDetection, AdBreak, JingleTemplate, DetectionStatistics
from apps.jingles.services import JingleDetector, AdBreakAnalyzer
from apps.notifications.services import NotificationService
from apps.streams.models import StreamSession


# Set up logging for jingle tasks
logger = logging.getLogger('stream_processor.jingle_tasks')


@shared_task
def process_pending_ad_breaks():
    """
    Process pending ad breaks and identify those that need completion.
    
    This periodic task looks for ad breaks that have been active too long
    without an end detection and completes them with estimated durations.
    
    Returns:
        dict: Processing results
    """
    try:
        logger.debug("Processing pending ad breaks")
        
        # Get all active stream sessions
        active_sessions = StreamSession.objects.filter(
            status__in=['active', 'processing']
        )
        
        total_processed = 0
        
        for session in active_sessions:
            try:
                # Initialize ad break analyzer for this session
                analyzer = AdBreakAnalyzer()
                
                # Clean up stale ad breaks (those active for more than 6 minutes)
                cleaned_count = analyzer.cleanup_stale_ad_breaks(session, timeout_minutes=6)
                total_processed += cleaned_count
                
                if cleaned_count > 0:
                    logger.info(f"Processed {cleaned_count} stale ad breaks for session {session.id}")
                    
            except Exception as e:
                logger.error(f"Failed to process ad breaks for session {session.id}: {e}")
                continue
        
        logger.debug(f"Ad break processing completed: {total_processed} breaks processed")
        
        return {
            'success': True,
            'ad_breaks_processed': total_processed
        }
        
    except Exception as e:
        logger.error(f"Ad break processing task failed: {e}")
        raise


@shared_task
def send_ad_break_notification(ad_break_id: str):
    """
    Send notification about a completed ad break to external systems.
    
    This task handles sending ad break data to external APIs and
    notification systems when an ad break is completed.
    
    Args:
        ad_break_id (str): UUID of the completed ad break
        
    Returns:
        dict: Notification results
    """
    try:
        logger.info(f"Sending ad break notification for: {ad_break_id}")
        
        # Get the ad break
        ad_break = AdBreak.objects.get(id=ad_break_id)
        
        if not ad_break.is_complete():
            logger.warning(f"Ad break {ad_break_id} is not complete, skipping notification")
            return {'success': False, 'reason': 'ad_break_not_complete'}
        
        # Initialize services
        analyzer = AdBreakAnalyzer()
        notification_service = NotificationService()
        
        # Get ad break data for external API
        ad_break_data = analyzer.get_ad_break_data(ad_break)
        
        # Send notification about the ad break
        notification_service.send_notification(
            template_type='ad_break_ended',
            context={
                'channel_name': ad_break.channel_name,
                'region': ad_break.region,
                'start_time': ad_break.start_time.isoformat(),
                'end_time': ad_break.end_time.isoformat() if ad_break.end_time else None,
                'duration_seconds': ad_break.duration_seconds,
                'ad_break_id': str(ad_break.id),
            }
        )
        
        # Send data to external API if configured
        dai_api_url = settings.EXTERNAL_APIS.get('DAI_API_URL')
        if dai_api_url:
            success = send_to_dai_api.delay(ad_break_data, dai_api_url)
            logger.info(f"Queued DAI API call for ad break {ad_break_id}")
        
        # Mark ad break as sent
        ad_break.is_sent_to_api = True
        ad_break.save(update_fields=['is_sent_to_api'])
        
        return {
            'success': True,
            'ad_break_id': str(ad_break.id),
            'duration': ad_break.duration_seconds,
            'external_api_queued': bool(dai_api_url)
        }
        
    except AdBreak.DoesNotExist:
        error_msg = f"Ad break with ID {ad_break_id} not found"
        logger.error(error_msg)
        raise Exception(error_msg)
        
    except Exception as e:
        logger.error(f"Ad break notification task failed: {e}")
        raise


@shared_task(bind=True, max_retries=3, default_retry_delay=30)
def send_to_dai_api(self, ad_break_data: Dict[str, Any], api_url: str):
    """
    Send ad break data to external DAI (Dynamic Ad Insertion) API.
    
    This task handles the external API integration for ad break data
    with automatic retry logic for failed requests.
    
    Args:
        ad_break_data (Dict[str, Any]): Ad break data to send
        api_url (str): External API endpoint URL
        
    Returns:
        dict: API response results
    """
    try:
        import requests
        
        logger.info(f"Sending ad break data to DAI API: {api_url}")
        
        # Send GET request to external API (matching original implementation)
        response = requests.get(
            api_url,
            params=ad_break_data,
            timeout=30,
            headers={'User-Agent': 'Stream-Processor/1.0'}
        )
        
        if response.status_code == 200:
            logger.info(f"Successfully sent ad break data to DAI API")
            return {
                'success': True,
                'status_code': response.status_code,
                'response_data': response.text[:500]  # Limit response data
            }
        else:
            error_msg = f"DAI API returned status {response.status_code}: {response.text[:200]}"
            logger.error(error_msg)
            
            # Retry if not a client error
            if response.status_code >= 500:
                if self.request.retries < self.max_retries:
                    logger.info(f"Retrying DAI API call (attempt {self.request.retries + 1})")
                    raise self.retry(exc=Exception(error_msg))
            
            return {
                'success': False,
                'status_code': response.status_code,
                'error_message': error_msg
            }
            
    except requests.RequestException as e:
        error_msg = f"DAI API request failed: {e}"
        logger.error(error_msg)
        
        # Retry for network errors
        if self.request.retries < self.max_retries:
            logger.info(f"Retrying DAI API call due to network error (attempt {self.request.retries + 1})")
            raise self.retry(exc=e)
        
        return {
            'success': False,
            'error_message': error_msg,
            'retries_exhausted': True
        }
        
    except Exception as e:
        logger.error(f"DAI API task failed: {e}")
        raise


@shared_task
def update_detection_statistics():
    """
    Update detection statistics for all jingle templates.
    
    This periodic task recalculates detection statistics to ensure
    accuracy metrics are up to date.
    
    Returns:
        dict: Statistics update results
    """
    try:
        logger.debug("Updating detection statistics")
        
        # Get all active jingle templates
        templates = JingleTemplate.objects.filter(is_active=True)
        
        updated_count = 0
        
        for template in templates:
            try:
                # Get all statistics records for this template
                stats_records = DetectionStatistics.objects.filter(template=template)
                
                for stats in stats_records:
                    # Update statistics
                    stats.update_statistics()
                    updated_count += 1
                    
            except Exception as e:
                logger.error(f"Failed to update statistics for template {template.name}: {e}")
                continue
        
        logger.info(f"Updated {updated_count} detection statistics records")
        
        return {
            'success': True,
            'statistics_updated': updated_count
        }
        
    except Exception as e:
        logger.error(f"Detection statistics update task failed: {e}")
        raise


@shared_task
def cleanup_old_detections():
    """
    Clean up old jingle detection records and files.
    
    This periodic task removes old detection records and associated
    frame files to manage disk space and database size.
    
    Returns:
        dict: Cleanup results
    """
    try:
        logger.debug("Cleaning up old jingle detections")
        
        from datetime import timedelta
        import os
        
        # Define retention periods
        detection_retention_days = 30
        frame_retention_days = 7
        
        cutoff_time_detections = timezone.now() - timedelta(days=detection_retention_days)
        cutoff_time_frames = timezone.now() - timedelta(days=frame_retention_days)
        
        # Clean up old detection records
        old_detections = JingleDetection.objects.filter(
            detection_time__lt=cutoff_time_detections
        )
        
        detection_count = old_detections.count()
        
        # Clean up frame files for very old detections (only for channels with jingle templates)
        frame_cleanup_count = 0
        for detection in JingleDetection.objects.filter(detection_time__lt=cutoff_time_frames):
            try:
                # Get the channel from the detection's session
                channel = detection.session.channel
                
                # Only delete iframes if the channel has active jingle templates
                if channel.jingle_templates.filter(is_active=True).exists():
                    if detection.frame_exists():
                        if detection.delete_frame():
                            frame_cleanup_count += 1
                else:
                    logger.debug(f"Preserving iframe for channel {channel.name} - no active jingle templates")
            except Exception as e:
                logger.warning(f"Failed to delete frame for detection {detection.id}: {e}")
        
        # Delete old detection records
        old_detections.delete()
        
        # Clean up completed ad breaks older than retention period
        old_ad_breaks = AdBreak.objects.filter(
            created_at__lt=cutoff_time_detections,
            status='completed'
        )
        
        ad_break_count = old_ad_breaks.count()
        old_ad_breaks.delete()
        
        logger.info(
            f"Cleanup completed: {detection_count} detections, "
            f"{frame_cleanup_count} frames, {ad_break_count} ad breaks"
        )
        
        return {
            'success': True,
            'detections_deleted': detection_count,
            'frames_deleted': frame_cleanup_count,
            'ad_breaks_deleted': ad_break_count
        }
        
    except Exception as e:
        logger.error(f"Detection cleanup task failed: {e}")
        raise


@shared_task
def validate_jingle_templates():
    """
    Validate jingle template files and update their status.
    
    This periodic task checks that jingle template image files
    exist and are accessible, updating the database accordingly.
    
    Returns:
        dict: Validation results
    """
    try:
        logger.debug("Validating jingle templates")
        
        # Get all jingle templates
        templates = JingleTemplate.objects.all()
        
        valid_count = 0
        invalid_count = 0
        
        for template in templates:
            try:
                # Check if template image file exists
                if template.image_exists():
                    # Ensure template is marked as active if file exists
                    if not template.is_active:
                        template.is_active = True
                        template.save(update_fields=['is_active'])
                        logger.info(f"Reactivated template {template.name} - file found")
                    valid_count += 1
                else:
                    # Mark template as inactive if file is missing
                    if template.is_active:
                        template.is_active = False
                        template.save(update_fields=['is_active'])
                        logger.warning(f"Deactivated template {template.name} - file missing")
                    invalid_count += 1
                    
            except Exception as e:
                logger.error(f"Failed to validate template {template.name}: {e}")
                invalid_count += 1
                continue
        
        logger.info(f"Template validation completed: {valid_count} valid, {invalid_count} invalid")
        
        return {
            'success': True,
            'valid_templates': valid_count,
            'invalid_templates': invalid_count
        }
        
    except Exception as e:
        logger.error(f"Template validation task failed: {e}")
        raise


@shared_task
def generate_detection_report():
    """
    Generate a periodic detection report with statistics and insights.
    
    This task creates comprehensive reports about jingle detection
    performance and ad break patterns.
    
    Returns:
        dict: Report data
    """
    try:
        logger.debug("Generating detection report")
        
        from datetime import timedelta
        
        # Get data for the last 24 hours
        end_time = timezone.now()
        start_time = end_time - timedelta(hours=24)
        
        # Get detection statistics
        recent_detections = JingleDetection.objects.filter(
            detection_time__gte=start_time
        )
        
        detection_count = recent_detections.count()
        confirmed_count = recent_detections.filter(is_confirmed=True).count()
        
        # Get ad break statistics
        recent_ad_breaks = AdBreak.objects.filter(
            start_time__gte=start_time
        )
        
        ad_break_count = recent_ad_breaks.count()
        completed_ad_breaks = recent_ad_breaks.filter(status='completed')
        
        # Calculate average ad break duration
        avg_duration = None
        if completed_ad_breaks.exists():
            durations = [ab.duration_seconds for ab in completed_ad_breaks if ab.duration_seconds]
            if durations:
                avg_duration = sum(durations) / len(durations)
        
        # Get template performance
        template_stats = {}
        for template in JingleTemplate.objects.filter(is_active=True):
            template_detections = recent_detections.filter(template=template)
            template_stats[template.name] = {
                'detections': template_detections.count(),
                'confirmed': template_detections.filter(is_confirmed=True).count(),
            }
        
        # Send report notification
        notification_service = NotificationService()
        notification_service.send_notification(
            template_type='system_alert',
            context={
                'report_type': 'detection_report',
                'period_hours': 24,
                'total_detections': detection_count,
                'confirmed_detections': confirmed_count,
                'total_ad_breaks': ad_break_count,
                'avg_ad_duration': round(avg_duration, 1) if avg_duration else None,
                'template_performance': template_stats,
                'timestamp': timezone.now().isoformat(),
            }
        )
        
        return {
            'success': True,
            'detections': detection_count,
            'confirmed_detections': confirmed_count,
            'ad_breaks': ad_break_count,
            'avg_duration': avg_duration,
            'template_stats': template_stats
        }
        
    except Exception as e:
        logger.error(f"Detection report generation failed: {e}")
        raise
