"""
Notification Celery Tasks.
Async tasks for sending and managing notifications.
"""
import logging
from datetime import timedelta

from celery import shared_task
from django.utils import timezone

logger = logging.getLogger('notification.tasks')


@shared_task(
    bind=True,
    max_retries=3,
    default_retry_delay=60,
    autoretry_for=(Exception,),
    retry_backoff=True,
    retry_backoff_max=900,  # Max 15 minutes
)
def send_notification_task(self, notification_id: str) -> dict:
    """
    Send a notification asynchronously.
    
    Args:
        notification_id: UUID of the notification to send
        
    Returns:
        Dictionary with status and message
    """
    from .models import Notification, NotificationStatus
    from .services import notification_service
    
    try:
        notification = Notification.objects.get(id=notification_id)
    except Notification.DoesNotExist:
        logger.error(f"Notification not found: {notification_id}")
        return {"status": "error", "message": "Notification not found"}
    
    if notification.status not in [NotificationStatus.PENDING]:
        logger.info(f"Notification {notification_id} already processed")
        return {"status": "skipped", "message": "Already processed"}
    
    success = notification_service._deliver(notification, notification.user)
    
    if success:
        return {"status": "success", "message": "Sent"}
    else:
        # Increment retry count in log
        log = notification.logs.order_by('-created_at').first()
        if log:
            log.retry_count += 1
            log.save(update_fields=['retry_count'])
        
        # Raise for retry if not max retries
        if self.request.retries < self.max_retries:
            raise self.retry()
        
        return {"status": "failed", "message": "Max retries reached"}


@shared_task
def send_scheduled_notifications_task() -> dict:
    """
    Process scheduled notifications that are due.
    Runs periodically via Celery Beat.
    
    Returns:
        Dictionary with count of processed notifications
    """
    from .models import Notification, NotificationStatus
    
    now = timezone.now()
    
    # Find due notifications
    notifications = Notification.objects.filter(
        status=NotificationStatus.PENDING,
        scheduled_at__isnull=False,
        scheduled_at__lte=now,
    )
    
    count = 0
    for notification in notifications:
        send_notification_task.delay(str(notification.id))
        count += 1
    
    logger.info(f"Queued {count} scheduled notifications")
    return {"status": "success", "queued": count}


@shared_task(
    bind=True,
    max_retries=3,
)
def retry_failed_notifications_task(self) -> dict:
    """
    Retry failed notifications that haven't exceeded max retries.
    
    Returns:
        Dictionary with count of retried notifications
    """
    from .models import Notification, NotificationLog, NotificationStatus
    
    MAX_RETRIES = 3
    RETRY_WINDOW_HOURS = 24
    
    # Find failed notifications within retry window
    cutoff = timezone.now() - timedelta(hours=RETRY_WINDOW_HOURS)
    
    failed_notifications = Notification.objects.filter(
        status=NotificationStatus.FAILED,
        created_at__gte=cutoff,
    )
    
    count = 0
    for notification in failed_notifications:
        # Check retry count
        log = notification.logs.order_by('-created_at').first()
        if log and log.retry_count < MAX_RETRIES:
            # Reset status and retry
            notification.status = NotificationStatus.PENDING
            notification.save(update_fields=['status'])
            
            send_notification_task.delay(str(notification.id))
            count += 1
    
    logger.info(f"Retrying {count} failed notifications")
    return {"status": "success", "retried": count}


@shared_task
def cleanup_old_logs_task() -> dict:
    """
    Clean up notification logs older than retention period.
    Default retention: 90 days
    
    Returns:
        Dictionary with count of deleted logs
    """
    from .models import NotificationLog
    
    RETENTION_DAYS = 90
    
    cutoff = timezone.now() - timedelta(days=RETENTION_DAYS)
    
    deleted, _ = NotificationLog.objects.filter(
        created_at__lt=cutoff,
    ).delete()
    
    logger.info(f"Deleted {deleted} old notification logs")
    return {"status": "success", "deleted": deleted}


@shared_task
def cleanup_old_notifications_task() -> dict:
    """
    Clean up read panel notifications older than retention period.
    Default retention: 90 days
    
    Returns:
        Dictionary with count of deleted notifications
    """
    from .models import Notification, NotificationChannel
    
    RETENTION_DAYS = 90
    
    cutoff = timezone.now() - timedelta(days=RETENTION_DAYS)
    
    # Only delete read panel notifications
    deleted, _ = Notification.objects.filter(
        channel=NotificationChannel.PANEL,
        is_read=True,
        created_at__lt=cutoff,
    ).delete()
    
    logger.info(f"Deleted {deleted} old panel notifications")
    return {"status": "success", "deleted": deleted}
