import pytest
from django.utils import timezone

from apps.alerts.incident_log_builder import IncidentLogBuilder
from apps.alerts.models import EscalationPolicy
from apps.base.models import UserNotificationPolicy, UserNotificationPolicyLogRecord


@pytest.mark.django_db
def test_escalation_plan_messaging_backends(
    make_organization_and_user,
    make_user_notification_policy,
    make_escalation_chain,
    make_escalation_policy,
    make_channel_filter,
    make_alert_receive_channel,
    make_alert_group,
):
    organization, user = make_organization_and_user()
    make_user_notification_policy(
        user,
        UserNotificationPolicy.Step.NOTIFY,
        notify_by=UserNotificationPolicy.NotificationChannel.TESTONLY,
    )
    escalation_chain = make_escalation_chain(organization=organization)
    escalation_policy = make_escalation_policy(
        escalation_chain=escalation_chain,
        escalation_policy_step=EscalationPolicy.STEP_NOTIFY_USERS_QUEUE,
        last_notified_user=user,
    )
    escalation_policy.notify_to_users_queue.set([user])
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    channel_filter = make_channel_filter(alert_receive_channel, escalation_chain=escalation_chain)
    alert_group = make_alert_group(alert_receive_channel, channel_filter=channel_filter)
    alert_group.raw_escalation_snapshot = alert_group.build_raw_escalation_snapshot()
    alert_group.save()

    log_builder = IncidentLogBuilder(alert_group=alert_group)
    plan = log_builder.get_incident_escalation_plan()
    assert list(plan.values()) == [["send test only backend message to {}".format(user.username)]]


@pytest.mark.django_db
def test_get_notification_plan_for_user_with_bundled_notification(
    make_organization_and_user,
    make_user_notification_bundle,
    make_user_notification_policy,
    make_alert_receive_channel,
    make_alert_group,
    make_user_notification_policy_log_record,
):
    """
    Test building notification plan when one of the notifications was bundled:
    - test that scheduled but not triggered bundled notification appears in notification plan
    """

    organization, user = make_organization_and_user()
    alert_receive_channel = make_alert_receive_channel(organization)
    alert_group = make_alert_group(alert_receive_channel)

    log_builder = IncidentLogBuilder(alert_group)

    notification_bundle = make_user_notification_bundle(user, UserNotificationPolicy.NotificationChannel.SMS)
    notification_policy_sms = make_user_notification_policy(
        user, UserNotificationPolicy.Step.NOTIFY, notify_by=UserNotificationPolicy.NotificationChannel.SMS
    )
    notification_policy_slack = make_user_notification_policy(
        user, UserNotificationPolicy.Step.NOTIFY, notify_by=UserNotificationPolicy.NotificationChannel.SLACK
    )
    make_user_notification_policy(user, UserNotificationPolicy.Step.WAIT, wait_delay=timezone.timedelta(minutes=5))
    make_user_notification_policy(
        user, UserNotificationPolicy.Step.NOTIFY, notify_by=UserNotificationPolicy.NotificationChannel.PHONE_CALL
    )

    # bundled SMS notification has been scheduled, the second notification step "Notify by Slack" has not been passed
    # SMS notification should appear in notification plan with timedelta=2min
    bundled_sms_notification = notification_bundle.notifications.create(
        alert_group=alert_group,
        notification_policy=notification_policy_sms,
        alert_receive_channel=alert_receive_channel,
    )
    notification_plan_dict = log_builder._get_notification_plan_for_user(user)
    expected_plan_dict = {
        timezone.timedelta(0): [
            {
                "user_id": user.id,
                "plan_lines": [f"invite {user.username} in Slack"],
                "is_the_first_notification_step": False,
            }
        ],
        timezone.timedelta(seconds=120): [{"user_id": user.id, "plan_lines": [f"send sms to {user.username}"]}],
        timezone.timedelta(seconds=300): [{"user_id": user.id, "plan_lines": [f"call {user.username} by phone"]}],
    }
    assert notification_plan_dict == expected_plan_dict

    # the second notification step "Notify by Slack" has been passed
    make_user_notification_policy_log_record(
        author=user,
        alert_group=alert_group,
        notification_policy=notification_policy_slack,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
    )
    notification_plan_dict = log_builder._get_notification_plan_for_user(user)
    expected_plan_dict = {
        timezone.timedelta(0): [{"user_id": user.id, "plan_lines": [], "is_the_first_notification_step": False}],
        timezone.timedelta(seconds=120): [{"user_id": user.id, "plan_lines": [f"send sms to {user.username}"]}],
        timezone.timedelta(seconds=300): [{"user_id": user.id, "plan_lines": [f"call {user.username} by phone"]}],
    }
    assert notification_plan_dict == expected_plan_dict

    # bundled SMS notification has been triggered, it should not appear in notification plan anymore
    make_user_notification_policy_log_record(
        author=user,
        alert_group=alert_group,
        notification_policy=notification_policy_sms,
        type=UserNotificationPolicyLogRecord.TYPE_PERSONAL_NOTIFICATION_TRIGGERED,
    )
    bundled_sms_notification.bundle_uuid = "test_bundle_uuid"
    bundled_sms_notification.save()

    notification_plan_dict = log_builder._get_notification_plan_for_user(user)
    expected_plan_dict = {
        timezone.timedelta(0): [{"user_id": user.id, "plan_lines": [], "is_the_first_notification_step": False}],
        timezone.timedelta(seconds=300): [{"user_id": user.id, "plan_lines": [f"call {user.username} by phone"]}],
    }
    assert notification_plan_dict == expected_plan_dict


@pytest.mark.django_db
def test_escalation_plan_custom_webhooks(
    make_organization_and_user,
    make_escalation_chain,
    make_escalation_policy,
    make_custom_webhook,
    make_alert_receive_channel,
    make_channel_filter,
    make_alert_group,
):
    organization, user = make_organization_and_user()
    escalation_chain = make_escalation_chain(organization=organization)
    custom_webhook = make_custom_webhook(organization=organization)
    make_escalation_policy(
        escalation_chain=escalation_chain,
        escalation_policy_step=EscalationPolicy.STEP_WAIT,
        wait_delay=EscalationPolicy.FIFTEEN_MINUTES,
    )
    make_escalation_policy(
        escalation_chain=escalation_chain,
        escalation_policy_step=EscalationPolicy.STEP_TRIGGER_CUSTOM_WEBHOOK,
        custom_webhook=custom_webhook,
    )
    alert_receive_channel = make_alert_receive_channel(organization=organization)
    channel_filter = make_channel_filter(alert_receive_channel, escalation_chain=escalation_chain)
    alert_group = make_alert_group(alert_receive_channel, channel_filter=channel_filter)
    alert_group.raw_escalation_snapshot = alert_group.build_raw_escalation_snapshot()
    alert_group.save()

    log_builder = IncidentLogBuilder(alert_group=alert_group)
    plan = log_builder.get_incident_escalation_plan()
    assert list(plan.values()) == [[f'trigger outgoing webhook "{custom_webhook.name}"']]
