"""PRD §5.1 FRFA-CO018 — overspend detection helpers."""
from datetime import date, timedelta
from decimal import Decimal

import pytest
from django.core.exceptions import ValidationError
from django.utils import timezone

from apps.rims.finance.models import Budget, BudgetLine, DisbursementRequest
from apps.rims.finance.services import (
    assert_award_has_no_overspend,
    finance_health_snapshot,
)
from apps.rims.grants.models import Application, GrantCall
from apps.rims.grants.services import (
    award_application,
    shortlist_application,
    submit_application,
)


def _award_budget(applicant_user, institution, *, ceiling: str, disbursed: str):
    call = GrantCall.objects.create(
        title="Overspend call",
        slug=f"ov-{int(timezone.now().timestamp() * 1000) % 10_000_000}",
        opens_at=timezone.now() - timedelta(days=1),
        closes_at=timezone.now() + timedelta(days=10),
        status=GrantCall.Status.PUBLISHED,
    )
    app = Application.objects.create(call=call, applicant=applicant_user, institution=institution)
    submit_application(app)
    app = Application.objects.get(pk=app.pk)
    shortlist_application(app)
    award_application(app, Decimal("1000"), date.today() + timedelta(days=180), narrative="")
    award = Application.objects.get(pk=app.pk).award
    budget = Budget.objects.create(award=award, name="Overspend budget")
    BudgetLine.objects.create(budget=budget, label="L", amount=Decimal(ceiling))
    DisbursementRequest.objects.create(
        budget=budget,
        amount=Decimal(disbursed),
        status=DisbursementRequest.Status.PAID,
    )
    return award, budget


@pytest.mark.django_db
def test_snapshot_flags_overspend(applicant_user, institution):
    award, budget = _award_budget(
        applicant_user, institution, ceiling="500", disbursed="700"
    )
    snap = finance_health_snapshot(budget)
    assert snap["overspend_flag"] is True
    assert snap["overspend_amount"] == Decimal("200")


@pytest.mark.django_db
def test_snapshot_no_flag_when_on_track(applicant_user, institution):
    award, budget = _award_budget(
        applicant_user, institution, ceiling="500", disbursed="400"
    )
    snap = finance_health_snapshot(budget)
    assert snap["overspend_flag"] is False
    assert snap["overspend_amount"] == Decimal("0")


@pytest.mark.django_db
def test_assert_award_has_no_overspend_raises(applicant_user, institution):
    award, _ = _award_budget(
        applicant_user, institution, ceiling="500", disbursed="700"
    )
    with pytest.raises(ValidationError):
        assert_award_has_no_overspend(award)


@pytest.mark.django_db
def test_assert_award_has_no_overspend_passes(applicant_user, institution):
    award, _ = _award_budget(
        applicant_user, institution, ceiling="500", disbursed="400"
    )
    # No raise.
    assert_award_has_no_overspend(award)
