"""
Celery Tasks for Notification Processing

This module contains Celery tasks for handling notification delivery,
retry logic, and maintenance operations for the notification system.
"""

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 .models import Notification, NotificationChannel, NotificationRule
from .services import NotificationService, TelegramService


# Set up logging for notification tasks
logger = logging.getLogger('stream_processor.notification_tasks')


@shared_task(bind=True, max_retries=5, default_retry_delay=60)
def send_telegram_message(self, message: str, chat_id: str = None):
    """
    Send a message via Telegram with retry logic.
    
    This task provides a simple interface for sending Telegram messages
    with automatic retry handling for failed deliveries.
    
    Args:
        message (str): Message text to send
        chat_id (str, optional): Target chat ID, uses default if not provided
        
    Returns:
        dict: Delivery result
    """
    try:
        logger.info("Sending Telegram message")
        
        # Initialize Telegram service
        telegram_service = TelegramService()
        
        # Send message
        result = telegram_service.send_message(message, chat_id)
        
        logger.info("Telegram message sent successfully")
        return {
            'success': True,
            'message_id': result.get('result', {}).get('message_id'),
            'chat_id': chat_id or telegram_service.default_chat_id
        }
        
    except Exception as e:
        logger.error(f"Failed to send Telegram message: {e}")
        
        # Retry if we haven't exceeded max retries
        if self.request.retries < self.max_retries:
            logger.info(f"Retrying Telegram message (attempt {self.request.retries + 1})")
            raise self.retry(exc=e)
        else:
            logger.error("Max retries exceeded for Telegram message")
            return {
                'success': False,
                'error': str(e),
                'retries_exhausted': True
            }


@shared_task(bind=True, max_retries=3, default_retry_delay=120)
def process_notification(self, notification_id: str):
    """
    Process and deliver a notification.
    
    This task handles the delivery of individual notifications through
    their configured channels with retry logic for failed deliveries.
    
    Args:
        notification_id (str): UUID of the notification to process
        
    Returns:
        dict: Processing result
    """
    try:
        logger.info(f"Processing notification: {notification_id}")
        
        # Get the notification
        notification = Notification.objects.get(id=notification_id)
        
        # Check if notification is already sent
        if notification.is_sent():
            logger.info(f"Notification {notification_id} already sent")
            return {'success': True, 'already_sent': True}
        
        # Initialize notification service
        notification_service = NotificationService()
        
        # Deliver the notification
        success = notification_service._deliver_notification(notification)
        
        if success:
            logger.info(f"Notification {notification_id} delivered successfully")
            return {
                'success': True,
                'notification_id': str(notification.id),
                'channel_type': notification.channel.channel_type,
                'sent_at': notification.sent_at.isoformat() if notification.sent_at else None
            }
        else:
            error_msg = f"Failed to deliver notification {notification_id}"
            logger.error(error_msg)
            
            # Retry if possible
            if notification.can_retry() and self.request.retries < self.max_retries:
                logger.info(f"Retrying notification delivery (attempt {self.request.retries + 1})")
                raise self.retry(exc=Exception(error_msg))
            
            return {
                'success': False,
                'notification_id': str(notification.id),
                'error': error_msg,
                'retries_exhausted': not notification.can_retry()
            }
            
    except Notification.DoesNotExist:
        error_msg = f"Notification with ID {notification_id} not found"
        logger.error(error_msg)
        return {'success': False, 'error': error_msg}
        
    except Exception as e:
        logger.error(f"Notification processing failed: {e}")
        
        # Retry for unexpected errors
        if self.request.retries < self.max_retries:
            logger.info(f"Retrying notification processing (attempt {self.request.retries + 1})")
            raise self.retry(exc=e)
        
        return {
            'success': False,
            'error': str(e),
            'retries_exhausted': True
        }


@shared_task
def process_pending_notifications():
    """
    Process all pending notifications that are ready for delivery.
    
    This periodic task finds notifications that are scheduled for
    delivery and queues them for processing.
    
    Returns:
        dict: Processing results
    """
    try:
        logger.debug("Processing pending notifications")
        
        # Find notifications ready for delivery
        pending_notifications = Notification.objects.filter(
            status='pending',
            scheduled_at__lte=timezone.now()
        ).order_by('scheduled_at')
        
        queued_count = 0
        
        for notification in pending_notifications:
            try:
                # Mark as processing
                notification.status = 'processing'
                notification.save(update_fields=['status'])
                
                # Queue for delivery
                process_notification.delay(str(notification.id))
                queued_count += 1
                
            except Exception as e:
                logger.error(f"Failed to queue notification {notification.id}: {e}")
                notification.mark_failed(f"Queue failed: {e}")
                continue
        
        logger.info(f"Queued {queued_count} notifications for processing")
        
        return {
            'success': True,
            'notifications_queued': queued_count
        }
        
    except Exception as e:
        logger.error(f"Pending notification processing failed: {e}")
        raise


@shared_task
def retry_failed_notifications():
    """
    Retry notifications that failed delivery but are eligible for retry.
    
    This periodic task identifies failed notifications that can be
    retried and queues them for another delivery attempt.
    
    Returns:
        dict: Retry results
    """
    try:
        logger.debug("Retrying failed notifications")
        
        # Initialize notification service
        notification_service = NotificationService()
        
        # Retry notifications from the last 24 hours
        retry_count = notification_service.retry_failed_notifications(max_age_hours=24)
        
        logger.info(f"Retried {retry_count} failed notifications")
        
        return {
            'success': True,
            'notifications_retried': retry_count
        }
        
    except Exception as e:
        logger.error(f"Failed notification retry task failed: {e}")
        raise


@shared_task
def cleanup_old_notifications():
    """
    Clean up old notification records to manage database size.
    
    This periodic task removes old notification records that are
    no longer needed for auditing or retry purposes.
    
    Returns:
        dict: Cleanup results
    """
    try:
        logger.debug("Cleaning up old notifications")
        
        from datetime import timedelta
        
        # Define retention periods
        sent_retention_days = 30  # Keep sent notifications for 30 days
        failed_retention_days = 7  # Keep failed notifications for 7 days
        
        # Calculate cutoff times
        sent_cutoff = timezone.now() - timedelta(days=sent_retention_days)
        failed_cutoff = timezone.now() - timedelta(days=failed_retention_days)
        
        # Clean up old sent notifications
        old_sent = Notification.objects.filter(
            status='completed',
            sent_at__lt=sent_cutoff
        )
        sent_count = old_sent.count()
        old_sent.delete()
        
        # Clean up old failed notifications (beyond retry window)
        old_failed = Notification.objects.filter(
            status='failed',
            created_at__lt=failed_cutoff
        )
        failed_count = old_failed.count()
        old_failed.delete()
        
        # Clean up cancelled notifications
        old_cancelled = Notification.objects.filter(
            status='cancelled',
            created_at__lt=failed_cutoff
        )
        cancelled_count = old_cancelled.count()
        old_cancelled.delete()
        
        total_deleted = sent_count + failed_count + cancelled_count
        
        logger.info(
            f"Notification cleanup completed: {sent_count} sent, "
            f"{failed_count} failed, {cancelled_count} cancelled (total: {total_deleted})"
        )
        
        return {
            'success': True,
            'sent_deleted': sent_count,
            'failed_deleted': failed_count,
            'cancelled_deleted': cancelled_count,
            'total_deleted': total_deleted
        }
        
    except Exception as e:
        logger.error(f"Notification cleanup task failed: {e}")
        raise


@shared_task
def validate_notification_channels():
    """
    Validate notification channel configurations and connectivity.
    
    This periodic task checks that notification channels are properly
    configured and can successfully deliver test messages.
    
    Returns:
        dict: Validation results
    """
    try:
        logger.debug("Validating notification channels")
        
        # Get all active notification channels
        channels = NotificationChannel.objects.filter(is_active=True)
        
        valid_count = 0
        invalid_count = 0
        validation_results = {}
        
        for channel in channels:
            try:
                channel_valid = True
                error_message = None
                
                if channel.channel_type == 'telegram':
                    # Validate Telegram configuration
                    config = channel.get_telegram_config()
                    if not config.get('bot_token') or not config.get('chat_id'):
                        channel_valid = False
                        error_message = "Missing bot_token or chat_id"
                    else:
                        # Test Telegram connection (optional)
                        try:
                            telegram_service = TelegramService(
                                bot_token=config['bot_token'],
                                chat_id=config['chat_id']
                            )
                            # Could send a test message here if needed
                        except Exception as e:
                            channel_valid = False
                            error_message = f"Telegram validation failed: {e}"
                
                elif channel.channel_type == 'email':
                    # Validate email configuration
                    config = channel.get_email_config()
                    if not config.get('recipients'):
                        channel_valid = False
                        error_message = "No recipients configured"
                
                elif channel.channel_type == 'webhook':
                    # Validate webhook configuration
                    config = channel.get_webhook_config()
                    if not config.get('url'):
                        channel_valid = False
                        error_message = "No webhook URL configured"
                
                # Update channel status if needed
                if channel_valid != channel.is_active:
                    channel.is_active = channel_valid
                    channel.save(update_fields=['is_active'])
                    
                    status_change = "activated" if channel_valid else "deactivated"
                    logger.info(f"Channel {channel.name} {status_change} based on validation")
                
                validation_results[channel.name] = {
                    'valid': channel_valid,
                    'error': error_message
                }
                
                if channel_valid:
                    valid_count += 1
                else:
                    invalid_count += 1
                    
            except Exception as e:
                logger.error(f"Failed to validate channel {channel.name}: {e}")
                validation_results[channel.name] = {
                    'valid': False,
                    'error': str(e)
                }
                invalid_count += 1
        
        logger.info(f"Channel validation completed: {valid_count} valid, {invalid_count} invalid")
        
        return {
            'success': True,
            'valid_channels': valid_count,
            'invalid_channels': invalid_count,
            'results': validation_results
        }
        
    except Exception as e:
        logger.error(f"Channel validation task failed: {e}")
        raise


@shared_task
def send_notification_via_rule(event_type: str, context: Dict[str, Any]):
    """
    Send notifications based on event type and notification rules.
    
    This task provides the main interface for triggering notifications
    from other parts of the system based on events and rules.
    
    Args:
        event_type (str): Type of event that occurred
        context (Dict[str, Any]): Event context data for templates
        
    Returns:
        dict: Notification results
    """
    try:
        logger.info(f"Processing notification for event: {event_type}")
        
        # Initialize notification service
        notification_service = NotificationService()
        
        # Send notification using rules
        success = notification_service.send_notification(
            template_type=event_type,
            context=context
        )
        
        if success:
            logger.info(f"Notification sent successfully for event: {event_type}")
            return {
                'success': True,
                'event_type': event_type,
                'context_keys': list(context.keys())
            }
        else:
            logger.warning(f"No notifications sent for event: {event_type}")
            return {
                'success': False,
                'event_type': event_type,
                'reason': 'no_applicable_rules_or_delivery_failed'
            }
            
    except Exception as e:
        logger.error(f"Rule-based notification failed: {e}")
        raise


@shared_task
def generate_notification_report():
    """
    Generate a periodic report about notification system performance.
    
    This task creates reports about notification delivery rates,
    channel performance, and system health.
    
    Returns:
        dict: Report data
    """
    try:
        logger.debug("Generating notification report")
        
        from datetime import timedelta
        
        # Get data for the last 24 hours
        end_time = timezone.now()
        start_time = end_time - timedelta(hours=24)
        
        # Get notification statistics
        total_notifications = Notification.objects.filter(
            created_at__gte=start_time
        ).count()
        
        sent_notifications = Notification.objects.filter(
            created_at__gte=start_time,
            status='completed'
        ).count()
        
        failed_notifications = Notification.objects.filter(
            created_at__gte=start_time,
            status='failed'
        ).count()
        
        pending_notifications = Notification.objects.filter(
            status='pending'
        ).count()
        
        # Calculate delivery rate
        delivery_rate = 0
        if total_notifications > 0:
            delivery_rate = (sent_notifications / total_notifications) * 100
        
        # Get channel performance
        channel_stats = {}
        for channel in NotificationChannel.objects.filter(is_active=True):
            channel_notifications = Notification.objects.filter(
                channel=channel,
                created_at__gte=start_time
            )
            
            channel_stats[channel.name] = {
                'total': channel_notifications.count(),
                'sent': channel_notifications.filter(status='completed').count(),
                'failed': channel_notifications.filter(status='failed').count(),
            }
        
        logger.info(f"Notification report: {delivery_rate:.1f}% delivery rate")
        
        return {
            'success': True,
            'period_hours': 24,
            'total_notifications': total_notifications,
            'sent_notifications': sent_notifications,
            'failed_notifications': failed_notifications,
            'pending_notifications': pending_notifications,
            'delivery_rate': round(delivery_rate, 1),
            'channel_performance': channel_stats,
            'timestamp': timezone.now().isoformat()
        }
        
    except Exception as e:
        logger.error(f"Notification report generation failed: {e}")
        raise
