from datetime import timedelta

from celery import shared_task
from django.conf import settings
from django.db.models import Count
from django.utils import timezone
from django_redis import get_redis_connection

from apps.issue_events.models import Issue

from .constants import ISSUE_IDS_KEY
from .models import Notification, ProjectAlert

# Lua script for atomic smembers + del
LUA_SCRIPT = """
local members = redis.call('SMEMBERS', KEYS[1])
redis.call('DEL', KEYS[1])
return members
"""


def process_alert(project_alert_id: int, issue_ids: list[int]):
    notification = Notification.objects.create(project_alert_id=project_alert_id)
    notification.issues.add(*issue_ids)
    send_notification.delay(notification.pk)


@shared_task
def process_event_alerts():
    """Inspect alerts and determine if new notifications need sent"""
    now = timezone.now()

    issue_ids: list[int] | None = None
    # Support not having redis, in theory
    if settings.CACHE_IS_REDIS:
        # Note all recent issue_ids at ingest time. Then we can filter by them here.
        issue_ids = [
            int(x)
            for x in get_redis_connection("default").eval(LUA_SCRIPT, 1, ISSUE_IDS_KEY)
        ]

    project_alerts = ProjectAlert.objects.filter(
        quantity__isnull=False, timespan_minutes__isnull=False
    )
    if issue_ids == []:
        return  # There are no new issues, no work to do

    if issue_ids:
        project_alerts = project_alerts.filter(
            project__issues__id__in=issue_ids
        ).distinct()

    for alert in project_alerts:
        start_time = now - timedelta(minutes=alert.timespan_minutes)
        quantity_in_timespan = alert.quantity
        issues = (
            Issue.objects.filter(
                project_id=alert.project_id,
                issueevent__received__gte=start_time,
            )
            .exclude(notification__project_alert=alert)
            .annotate(num_events=Count("issueevent"))
            .filter(num_events__gte=quantity_in_timespan)
        )
        if issue_ids:
            issues = issues.filter(id__in=issue_ids)
        if issues:
            notification = alert.notification_set.create()
            notification.issues.add(*issues)
            send_notification.delay(notification.pk)


@shared_task
def send_notification(notification_id: int):
    notification = Notification.objects.get(pk=notification_id)
    notification.send_notifications()
