"""G13 — Alert escalation tier transitions."""
from __future__ import annotations

from decimal import Decimal

import pytest
from django.contrib.auth import get_user_model

from apps.core.notifications.models import Notification
from apps.core.permissions.roles import UserRole
from apps.mel.indicators.models import (
    AlertEscalation,
    AlertEscalationRule,
    Indicator,
    IndicatorFrequency,
    LogFrame,
    LogFrameLevel,
    LogFrameRow,
    RagStatus,
)
from apps.mel.indicators.services import (
    acknowledge_escalation,
    dispatch_indicator_alert,
    escalate_alert,
)

User = get_user_model()
pytestmark = pytest.mark.django_db


@pytest.fixture
def users():
    return {
        "tier1": User.objects.create_user(email="g13-t1@example.com", password="x"),
        "tier2": User.objects.create_user(email="g13-t2@example.com", password="x"),
        "tier3": User.objects.create_user(email="g13-t3@example.com", password="x"),
        "ack": User.objects.create_user(email="g13-ack@example.com", password="x"),
    }


@pytest.fixture
def indicator(users):
    lf = LogFrame.objects.create(name="G13 LF", slug="g13-lf", owner=users["tier1"])
    impact = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.IMPACT, title="I")
    outcome = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.OUTCOME, title="O", parent=impact)
    output = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.OUTPUT, title="P", parent=outcome)
    ind = Indicator.objects.create(
        logframe_row=output, code="g13-i1", name="g13",
        unit="count", calculation_method="count", data_source="manual",
        frequency=IndicatorFrequency.MONTHLY,
        responsible=users["tier1"],
    )
    rule = AlertEscalationRule.objects.create(logframe=lf)
    rule.tier_1_recipients.add(users["tier1"])
    rule.tier_2_recipients.add(users["tier2"])
    rule.tier_3_recipients.add(users["tier3"])
    return ind


def test_dispatch_creates_tier1_escalation(indicator, users):
    progress = {"rag": RagStatus.RED, "percent": 12.5, "period_label": "2026-01"}
    dispatch_indicator_alert(indicator, progress)
    esc = AlertEscalation.objects.get(indicator=indicator, period_label="2026-01")
    assert esc.tier_reached == 1
    assert esc.acknowledged_at is None


def test_escalate_advances_to_tier2(indicator, users):
    dispatch_indicator_alert(indicator, {"rag": RagStatus.RED, "period_label": "2026-02"})
    esc = AlertEscalation.objects.get(indicator=indicator, period_label="2026-02")
    result = escalate_alert(esc.pk)
    assert result == "tier-2"
    esc.refresh_from_db()
    assert esc.tier_reached == 2
    assert Notification.objects.filter(
        recipient=users["tier2"],
        verb=Notification.Verb.MEL_INDICATOR_ESCALATION_TIER2,
    ).count() == 1


def test_escalate_advances_to_tier3(indicator, users):
    dispatch_indicator_alert(indicator, {"rag": RagStatus.RED, "period_label": "2026-03"})
    esc = AlertEscalation.objects.get(indicator=indicator, period_label="2026-03")
    escalate_alert(esc.pk)
    result = escalate_alert(esc.pk)
    assert result == "tier-3"
    esc.refresh_from_db()
    assert esc.tier_reached == 3
    assert Notification.objects.filter(
        recipient=users["tier3"],
        verb=Notification.Verb.MEL_INDICATOR_ESCALATION_TIER3,
    ).count() == 1


def test_acknowledge_stops_escalation(indicator, users):
    dispatch_indicator_alert(indicator, {"rag": RagStatus.RED, "period_label": "2026-04"})
    esc = AlertEscalation.objects.get(indicator=indicator, period_label="2026-04")
    acknowledge_escalation(esc, user=users["ack"])
    esc.refresh_from_db()
    assert esc.acknowledged_at is not None
    assert esc.acknowledged_by == users["ack"]
    # Subsequent escalation calls become no-ops.
    result = escalate_alert(esc.pk)
    assert result == "acknowledged"
    esc.refresh_from_db()
    assert esc.tier_reached == 1


def test_dispatch_idempotent_on_replay(indicator, users):
    dispatch_indicator_alert(indicator, {"rag": RagStatus.RED, "period_label": "2026-05"})
    dispatch_indicator_alert(indicator, {"rag": RagStatus.RED, "period_label": "2026-05"})
    assert AlertEscalation.objects.filter(
        indicator=indicator, period_label="2026-05",
    ).count() == 1


def test_no_escalation_when_no_rule(users):
    """No AlertEscalationRule on the logframe → no escalation row created."""
    lf = LogFrame.objects.create(name="g13-no-rule", slug="g13-no-rule", owner=users["tier1"])
    impact = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.IMPACT, title="I")
    outcome = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.OUTCOME, title="O", parent=impact)
    output = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.OUTPUT, title="P", parent=outcome)
    ind = Indicator.objects.create(
        logframe_row=output, code="g13-no-rule-1", name="x",
        unit="count", calculation_method="count", data_source="manual",
        frequency=IndicatorFrequency.MONTHLY, responsible=users["tier1"],
    )
    dispatch_indicator_alert(ind, {"rag": RagStatus.RED, "period_label": "2026-06"})
    assert AlertEscalation.objects.filter(indicator=ind).count() == 0
