from unittest.mock import patch

import pytest
from django.utils import timezone
from telegram.error import RetryAfter

from apps.alerts.models import AlertGroup
from apps.alerts.paging import direct_paging
from apps.alerts.tasks.notify_user import notify_user_task, perform_notification, send_bundled_notification
from apps.api.permissions import LegacyAccessControlRole
from apps.base.models.user_notification_policy import UserNotificationPolicy
from apps.base.models.user_notification_policy_log_record import UserNotificationPolicyLogRecord
from apps.slack.models import SlackMessage
from apps.telegram.models import TelegramToUserConnector

NOTIFICATION_UNAUTHORIZED_MSG = "notification is not allowed for user"


@pytest.mark.django_db
def test_custom_backend_call(
    make_organization,
    make_user,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
):
    organization = make_organization()
    user_1 = make_user(organization=organization)
    user_notification_policy = make_user_notification_policy(
        user=user_1,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.TESTONLY,
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)
    log_record = make_user_notification_policy_log_record(
        author=user_1,
        alert_group=alert_group,
        notification_policy=user_notification_policy,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
    )

    with patch("apps.base.tests.messaging_backend.TestOnlyBackend.notify_user") as mock_notify_user:
        perform_notification(log_record.pk, False)

    mock_notify_user.assert_called_once_with(user_1, alert_group, user_notification_policy)


@pytest.mark.django_db
def test_custom_backend_error(
    make_organization,
    make_user,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
):
    organization = make_organization()
    user_1 = make_user(organization=organization)
    user_notification_policy = make_user_notification_policy(
        user=user_1,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.TESTONLY,
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)
    log_record = make_user_notification_policy_log_record(
        author=user_1,
        alert_group=alert_group,
        notification_policy=user_notification_policy,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
    )

    with patch("apps.alerts.tasks.notify_user.get_messaging_backend_from_id") as mock_get_backend:
        mock_get_backend.return_value = None
        perform_notification(log_record.pk, False)

    error_log_record = UserNotificationPolicyLogRecord.objects.last()
    assert error_log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED
    assert error_log_record.reason == "Messaging backend not available"
    assert (
        error_log_record.notification_error_code
        == UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_MESSAGING_BACKEND_ERROR
    )


@pytest.mark.django_db
@pytest.mark.parametrize(
    "author_set,notification_policy_set",
    [
        (False, True),
        (True, False),
    ],
)
def test_notify_user_missing_data_errors(
    make_organization,
    make_user,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
    author_set,
    notification_policy_set,
):
    organization = make_organization()
    user_1 = make_user(organization=organization)
    user_notification_policy = make_user_notification_policy(
        user=user_1,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SMS,
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)
    log_record = make_user_notification_policy_log_record(
        author=user_1 if author_set else None,
        alert_group=alert_group,
        notification_policy=user_notification_policy if notification_policy_set else None,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
    )

    with patch("apps.alerts.tasks.notify_user.get_messaging_backend_from_id") as mock_get_backend:
        mock_get_backend.return_value = None
        perform_notification(log_record.pk, False)

    error_log_record = UserNotificationPolicyLogRecord.objects.last()
    assert error_log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED
    assert error_log_record.reason == "Expected data is missing"
    assert error_log_record.notification_error_code is None


@pytest.mark.django_db
def test_notify_user_perform_notification_error_if_viewer(
    make_organization,
    make_user,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
):
    organization = make_organization()
    user_1 = make_user(
        organization=organization, role=LegacyAccessControlRole.VIEWER, _verified_phone_number="1234567890"
    )
    user_notification_policy = make_user_notification_policy(
        user=user_1,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SMS,
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)
    log_record = make_user_notification_policy_log_record(
        author=user_1,
        alert_group=alert_group,
        notification_policy=user_notification_policy,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
    )

    perform_notification(log_record.pk, False)

    error_log_record = UserNotificationPolicyLogRecord.objects.last()
    assert error_log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED
    assert error_log_record.reason == NOTIFICATION_UNAUTHORIZED_MSG
    assert error_log_record.notification_error_code == UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_FORBIDDEN


@pytest.mark.django_db
def test_notify_user_error_if_viewer(
    make_organization,
    make_user,
    make_alert_receive_channel,
    make_alert_group,
):
    organization = make_organization()
    user_1 = make_user(
        organization=organization, role=LegacyAccessControlRole.VIEWER, _verified_phone_number="1234567890"
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)

    notify_user_task(user_1.pk, alert_group.pk)

    error_log_record = UserNotificationPolicyLogRecord.objects.last()
    assert error_log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED
    assert error_log_record.reason == NOTIFICATION_UNAUTHORIZED_MSG
    assert error_log_record.notification_error_code == UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_FORBIDDEN


@pytest.mark.django_db
@pytest.mark.parametrize(
    "reason_to_skip_escalation,error_code",
    [
        (AlertGroup.RATE_LIMITED, UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_IN_SLACK_RATELIMIT),
        (AlertGroup.CHANNEL_ARCHIVED, UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_IN_SLACK_CHANNEL_IS_ARCHIVED),
        (AlertGroup.ACCOUNT_INACTIVE, UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_IN_SLACK_TOKEN_ERROR),
        (AlertGroup.RESTRICTED_ACTION, UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_IN_SLACK),
        (AlertGroup.NO_REASON, None),
    ],
)
def test_perform_notification_reason_to_skip_escalation_in_slack(
    reason_to_skip_escalation,
    error_code,
    make_organization,
    make_slack_team_identity,
    make_user,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
    make_slack_message,
):
    organization = make_organization()
    slack_team_identity = make_slack_team_identity()
    organization.slack_team_identity = slack_team_identity
    organization.save()
    user = make_user(organization=organization)
    user_notification_policy = make_user_notification_policy(
        user=user,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SLACK,
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)
    alert_group.reason_to_skip_escalation = reason_to_skip_escalation
    alert_group.save()
    log_record = make_user_notification_policy_log_record(
        author=user,
        alert_group=alert_group,
        notification_policy=user_notification_policy,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
    )
    if not error_code:
        make_slack_message(alert_group=alert_group, channel_id="test_channel_id", slack_id="test_slack_id")
    with patch.object(SlackMessage, "send_slack_notification") as mocked_send_slack_notification:
        perform_notification(log_record.pk, False)
    last_log_record = UserNotificationPolicyLogRecord.objects.last()

    if error_code:
        log_reason = f"Skipped escalation in Slack, reason: '{alert_group.get_reason_to_skip_escalation_display()}'"
        mocked_send_slack_notification.assert_not_called()
        assert last_log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED
        assert last_log_record.reason == log_reason
        assert last_log_record.notification_error_code == error_code
    else:
        mocked_send_slack_notification.assert_called()
        assert last_log_record.type != UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED


@pytest.mark.django_db
def test_perform_notification_slack_prevent_posting(
    make_organization,
    make_slack_team_identity,
    make_user,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
    make_slack_message,
):
    organization = make_organization()
    slack_team_identity = make_slack_team_identity()
    organization.slack_team_identity = slack_team_identity
    organization.save()
    user = make_user(organization=organization)
    user_notification_policy = make_user_notification_policy(
        user=user,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SLACK,
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)
    log_record = make_user_notification_policy_log_record(
        author=user,
        alert_group=alert_group,
        notification_policy=user_notification_policy,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
        slack_prevent_posting=True,
    )
    make_slack_message(alert_group=alert_group, channel_id="test_channel_id", slack_id="test_slack_id")

    with patch.object(SlackMessage, "send_slack_notification") as mocked_send_slack_notification:
        perform_notification(log_record.pk, False)

    mocked_send_slack_notification.assert_not_called()
    last_log_record = UserNotificationPolicyLogRecord.objects.last()
    assert last_log_record.type == UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_FAILED
    assert last_log_record.reason == "Prevented from posting in Slack"
    assert (
        last_log_record.notification_error_code
        == UserNotificationPolicyLogRecord.ERROR_NOTIFICATION_POSTING_TO_SLACK_IS_DISABLED
    )


@pytest.mark.django_db
def test_perform_notification_missing_user_notification_policy_log_record(caplog):
    invalid_pk = 12345
    perform_notification(invalid_pk, False)

    assert (
        f"perform_notification: log_record {invalid_pk} doesn't exist. Skipping remainder of task. "
        "The alert group associated with this log record may have been deleted."
    ) in caplog.text
    assert f"perform_notification: found record for {invalid_pk}" not in caplog.text


@pytest.mark.django_db
def test_perform_notification_telegram_retryafter_error(
    make_organization_and_user,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
):
    organization, user = make_organization_and_user()
    user_notification_policy = make_user_notification_policy(
        user=user,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.TELEGRAM,
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)
    log_record = make_user_notification_policy_log_record(
        author=user,
        alert_group=alert_group,
        notification_policy=user_notification_policy,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
    )
    countdown = 15
    exc = RetryAfter(countdown)
    with patch.object(TelegramToUserConnector, "notify_user", side_effect=exc) as mock_notify_user:
        with pytest.raises(RetryAfter):
            perform_notification(log_record.pk, False)

    mock_notify_user.assert_called_once_with(user, alert_group, user_notification_policy)
    assert alert_group.personal_log_records.last() == log_record


@patch("apps.base.models.UserNotificationPolicy.get_default_fallback_policy")
@patch("apps.base.tests.messaging_backend.TestOnlyBackend.notify_user")
@pytest.mark.django_db
def test_perform_notification_use_default_notification_policy_fallback(
    mock_notify_user,
    mock_get_default_fallback_policy,
    make_organization,
    make_user,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
):
    organization = make_organization()
    user = make_user(organization=organization)
    fallback_notification_policy = UserNotificationPolicy(
        user=user,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.TESTONLY,
        important=False,
        order=0,
    )

    mock_get_default_fallback_policy.return_value = fallback_notification_policy

    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)
    log_record = make_user_notification_policy_log_record(
        author=user,
        alert_group=alert_group,
        notification_policy=None,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
    )

    perform_notification(log_record.pk, True)

    mock_notify_user.assert_called_once_with(user, alert_group, fallback_notification_policy)


@pytest.mark.django_db
def test_notify_user_task_notification_bundle_is_enabled(
    make_organization_and_user,
    make_user_for_organization,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    settings,
):
    settings.FEATURE_NOTIFICATION_BUNDLE_ENABLED = True
    organization, user_1 = make_organization_and_user()
    user_2 = make_user_for_organization(organization)
    make_user_notification_policy(
        user=user_1,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SMS,  # channel is in NOTIFICATION_CHANNELS_TO_BUNDLE
    )
    make_user_notification_policy(
        user=user_1,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SMS,
        important=True,
    )
    make_user_notification_policy(
        user=user_2,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SLACK,  # channel is not in NOTIFICATION_CHANNELS_TO_BUNDLE
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group_1 = make_alert_group(alert_receive_channel=alert_receive_channel)
    alert_group_2 = make_alert_group(alert_receive_channel=alert_receive_channel)
    assert not user_1.notification_bundles.exists()
    # send 1st notification to user_1, check notification_bundle was created
    # without scheduling send_bundled_notification task
    notify_user_task(user_1.id, alert_group_1.id)
    assert user_1.notification_bundles.count() == 1
    notification_bundle = user_1.notification_bundles.first()
    assert notification_bundle.notification_task_id is None
    assert not notification_bundle.notifications.exists()
    # send 2nd notification to user_1, check bundled notification was attached to notification_bundle
    # and send_bundled_notification was scheduled
    notify_user_task(user_1.id, alert_group_2.id)
    notification_bundle.refresh_from_db()
    assert notification_bundle.notifications.count() == 1
    assert notification_bundle.notification_task_id is not None
    # send important notification to user_1, check new notification_bundle was created
    notify_user_task(user_1.id, alert_group_1.id, important=True)
    assert user_1.notification_bundles.count() == 2
    important_notification_bundle = user_1.notification_bundles.get(important=True)
    assert important_notification_bundle.notification_task_id is None
    assert not important_notification_bundle.notifications.exists()
    # send notification to user_2 (notification channel is not in NOTIFICATION_CHANNELS_TO_BUNDLE),
    # check notification_bundle was not created
    notify_user_task(user_2.id, alert_group_1.id)
    assert not user_2.notification_bundles.exists()


@pytest.mark.django_db
def test_notify_user_task_notification_bundle_is_not_enabled(
    make_organization_and_user,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    settings,
):
    settings.FEATURE_NOTIFICATION_BUNDLE_ENABLED = False
    organization, user = make_organization_and_user()
    make_user_notification_policy(
        user=user,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SMS,  # channel is in NOTIFICATION_CHANNELS_TO_BUNDLE
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)

    # send notification, check notification_bundle was not created
    notify_user_task(user.id, alert_group.id)
    assert not user.notification_bundles.exists()


@pytest.mark.django_db
def test_send_bundle_notification(
    make_organization_and_user,
    make_user_notification_policy,
    make_user_notification_bundle,
    make_alert_receive_channel,
    make_alert_group,
    settings,
    caplog,
):
    settings.FEATURE_NOTIFICATION_BUNDLE_ENABLED = True
    organization, user = make_organization_and_user()
    notification_policy = make_user_notification_policy(
        user=user,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SMS,  # channel is in NOTIFICATION_CHANNELS_TO_BUNDLE
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group_1 = make_alert_group(alert_receive_channel=alert_receive_channel)
    alert_group_2 = make_alert_group(alert_receive_channel=alert_receive_channel)
    alert_group_3 = make_alert_group(alert_receive_channel=alert_receive_channel)
    notification_bundle = make_user_notification_bundle(
        user, UserNotificationPolicy.NotificationChannel.SMS, notification_task_id="test_task_id", eta=timezone.now()
    )
    notification_bundle.append_notification(alert_group_1, notification_policy)
    notification_bundle.append_notification(alert_group_2, notification_policy)
    notification_bundle.append_notification(alert_group_3, notification_policy)
    assert notification_bundle.notifications.filter(bundle_uuid__isnull=True).count() == 3
    alert_group_3.resolve()
    with patch("apps.alerts.tasks.notify_user.compare_escalations", return_value=True):
        # send notification for 2 active alert groups
        send_bundled_notification(notification_bundle.id)
        assert f"alert_group {alert_group_3.id} is not active, skip notification" in caplog.text
        assert "perform bundled notification for alert groups with ids:" in caplog.text
        # check bundle_uuid was set, notification for resolved alert group was deleted
        assert notification_bundle.notifications.filter(bundle_uuid__isnull=True).count() == 0
        assert notification_bundle.notifications.all().count() == 2
        assert not notification_bundle.notifications.filter(alert_group=alert_group_3).exists()

        # send notification for 1 active alert group
        notification_bundle.notifications.update(bundle_uuid=None)
        alert_group_2.resolve()
        send_bundled_notification(notification_bundle.id)
        assert f"alert_group {alert_group_2.id} is not active, skip notification" in caplog.text
        assert (
            f"there is only one alert group in bundled notification, perform regular notification. "
            f"alert_group {alert_group_1.id}"
        ) in caplog.text
        # check bundle_uuid was set
        assert notification_bundle.notifications.filter(bundle_uuid__isnull=True).count() == 0
        assert notification_bundle.notifications.all().count() == 1
        # cleanup notifications
        notification_bundle.notifications.all().delete()

        # send notification for 0 active alert group
        notification_bundle.append_notification(alert_group_1, notification_policy)
        alert_group_1.resolve()
        send_bundled_notification(notification_bundle.id)
        assert f"alert_group {alert_group_1.id} is not active, skip notification" in caplog.text
        assert f"no alert groups to notify about or notification is not allowed for user {user.id}" in caplog.text
        # check all notifications were deleted
        assert notification_bundle.notifications.all().count() == 0


@pytest.mark.django_db
def test_send_bundle_notification_task_id_mismatch(
    make_organization_and_user,
    make_user_notification_bundle,
    settings,
    caplog,
):
    settings.FEATURE_NOTIFICATION_BUNDLE_ENABLED = True
    organization, user = make_organization_and_user()
    notification_bundle = make_user_notification_bundle(
        user, UserNotificationPolicy.NotificationChannel.SMS, notification_task_id="test_task_id", eta=timezone.now()
    )
    send_bundled_notification(notification_bundle.id)
    assert (
        f"send_bundled_notification: notification_task_id mismatch. "
        f"Duplication or non-active notification triggered. "
        f"Active: {notification_bundle.notification_task_id}"
    ) in caplog.text


@pytest.mark.django_db
def test_notify_user_task_notification_bundle_eta_is_outdated(
    make_organization_and_user,
    make_user_for_organization,
    make_user_notification_policy,
    make_user_notification_bundle,
    make_alert_receive_channel,
    make_alert_group,
    settings,
):
    settings.FEATURE_NOTIFICATION_BUNDLE_ENABLED = True
    organization, user = make_organization_and_user()
    notification_policy = make_user_notification_policy(
        user=user,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.SMS,  # channel is in NOTIFICATION_CHANNELS_TO_BUNDLE
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group_1 = make_alert_group(alert_receive_channel=alert_receive_channel)
    alert_group_2 = make_alert_group(alert_receive_channel=alert_receive_channel)
    now = timezone.now()
    outdated_eta = now - timezone.timedelta(minutes=5)
    test_task_id = "test_task_id"
    notification_bundle = make_user_notification_bundle(
        user,
        UserNotificationPolicy.NotificationChannel.SMS,
        eta=outdated_eta,
        notification_task_id=test_task_id,
        last_notified_at=now,
    )
    notification_bundle.append_notification(alert_group_1, notification_policy)
    assert not notification_bundle.eta_is_valid()
    assert notification_bundle.notifications.count() == 1

    # call notify_user_task and check that new notification task for notification_bundle was scheduled
    notify_user_task(user.id, alert_group_2.id)
    notification_bundle.refresh_from_db()
    assert notification_bundle.eta_is_valid()
    assert notification_bundle.notification_task_id != test_task_id
    assert notification_bundle.last_notified_at == now
    assert notification_bundle.notifications.count() == 2


@patch.object(perform_notification, "apply_async")
@pytest.mark.django_db
def test_notify_user_task_direct_paging_acknowledged(
    mock_perform_notification_apply_async,
    make_organization,
    make_user,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
    make_user_notification_policy,
    django_capture_on_commit_callbacks,
):
    organization = make_organization()
    from_user = make_user(organization=organization)
    user1 = make_user(organization=organization)
    user2 = make_user(organization=organization)
    make_user_notification_policy(
        user=user1,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.TESTONLY,
    )
    make_user_notification_policy(
        user=user2,
        step=UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.TESTONLY,
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    alert_group = make_alert_group(alert_receive_channel=alert_receive_channel)

    direct_paging(organization, from_user, "Test", alert_group=alert_group, users=[(user1, False), (user2, False)])
    alert_group.acknowledge_by_user_or_backsync(user1)

    # no notification should be sent for user1 because they have acknowledged the alert group
    with django_capture_on_commit_callbacks(execute=True):
        notify_user_task(user1.pk, alert_group.pk, notify_even_acknowledged=True)

    mock_perform_notification_apply_async.assert_not_called()

    # user2 should receive a notification because they have not acknowledged the alert group
    with django_capture_on_commit_callbacks(execute=True):
        notify_user_task(user2.pk, alert_group.pk, notify_even_acknowledged=True)

    mock_perform_notification_apply_async.assert_called_once()
