"""WS2 defect #23 — nightly sweep flips past-due open OutputDeliverables to
OVERDUE (previously only derived lazily when progress was recorded).
"""
from __future__ import annotations

from datetime import date, timedelta
from decimal import Decimal

import pytest

from apps.mel.indicators.models import LogFrame, LogFrameLevel, LogFrameRow
from apps.mel.tracking.models import OutputDeliverable, OutputDeliverableStatus
from apps.mel.tracking.services import scan_overdue_outputs

pytestmark = pytest.mark.django_db

_N = {"n": 0}


def _output_row():
    _N["n"] += 1
    lf = LogFrame.objects.create(name=f"LF-{_N['n']}", slug=f"lf-ovd-{_N['n']}")
    impact = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.IMPACT, title="I")
    outcome = LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.OUTCOME, title="O", parent=impact)
    return LogFrameRow.objects.create(logframe=lf, level=LogFrameLevel.OUTPUT, title="P", parent=outcome)


def _deliverable(status, due_date, achieved=Decimal("5"), target=Decimal("20")):
    return OutputDeliverable.objects.create(
        logframe_row=_output_row(), title="T", target_quantity=target,
        achieved_quantity=achieved, unit="packs", due_date=due_date, status=status,
    )


def test_past_due_in_progress_flips_to_overdue():
    yesterday = date.today() - timedelta(days=1)
    d = _deliverable(OutputDeliverableStatus.IN_PROGRESS, yesterday)
    flagged = scan_overdue_outputs()
    assert flagged == 1
    assert OutputDeliverable.objects.get(pk=d.pk).status == OutputDeliverableStatus.OVERDUE


def test_past_due_draft_flips_to_overdue():
    d = _deliverable(OutputDeliverableStatus.DRAFT, date.today() - timedelta(days=3), achieved=Decimal("0"))
    scan_overdue_outputs()
    assert OutputDeliverable.objects.get(pk=d.pk).status == OutputDeliverableStatus.OVERDUE


def test_future_due_untouched():
    d = _deliverable(OutputDeliverableStatus.IN_PROGRESS, date.today() + timedelta(days=5))
    assert scan_overdue_outputs() == 0
    assert OutputDeliverable.objects.get(pk=d.pk).status == OutputDeliverableStatus.IN_PROGRESS


def test_completed_untouched():
    d = _deliverable(OutputDeliverableStatus.COMPLETED, date.today() - timedelta(days=10), achieved=Decimal("20"))
    assert scan_overdue_outputs() == 0
    assert OutputDeliverable.objects.get(pk=d.pk).status == OutputDeliverableStatus.COMPLETED


def test_fully_achieved_but_open_not_flagged():
    # Achieved >= target: leave for the progress path to close, not "overdue".
    d = _deliverable(OutputDeliverableStatus.IN_PROGRESS, date.today() - timedelta(days=2), achieved=Decimal("20"))
    assert scan_overdue_outputs() == 0
    assert OutputDeliverable.objects.get(pk=d.pk).status == OutputDeliverableStatus.IN_PROGRESS
