"""Read-only reconciliation view surfacing the gap between grants.AwardTranche
(the tranche/milestone plan) and finance.DisbursementRequest (what finance
actually paid) — there's no direct FK between the two today (only a
TrancheBudgetAllocation bridge via BudgetLine), so the two can drift apart
unnoticed. This view doesn't change data; it just flags mismatches by award.
"""
from datetime import timedelta
from decimal import Decimal

import pytest
from django.urls import reverse
from django.utils import timezone

from apps.rims.finance.models import Budget, DisbursementRequest, FundingSource
from apps.rims.grants.models import Application, AwardTranche, GrantCall
from apps.rims.grants.services import award_application, shortlist_application, submit_application


def _award_for(applicant_user, institution, *, suffix="recon"):
    call = GrantCall.objects.create(
        title="Reconciliation call",
        slug=f"recon-{suffix}-{int(timezone.now().timestamp())}",
        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"), timezone.now().date() + timedelta(days=180), narrative="")
    return Application.objects.get(pk=app.pk).award


@pytest.mark.django_db
def test_reconciliation_flags_mismatch(client, finance_user, applicant_user, institution):
    award = _award_for(applicant_user, institution, suffix="mismatch")
    AwardTranche.objects.create(award=award, label="Tranche 1", amount=Decimal("400"))
    AwardTranche.objects.create(award=award, label="Tranche 2", amount=Decimal("600"))
    donor = FundingSource.objects.create(name=f"Donor {award.pk}", code=f"donor-{award.pk}")
    budget = Budget.objects.create(award=award, name="Recon budget", funding_source=donor, currency=award.currency)
    DisbursementRequest.objects.create(
        budget=budget, amount=Decimal("400"), status=DisbursementRequest.Status.PAID,
    )

    client.force_login(finance_user)
    resp = client.get(reverse("rims_finance:tranche_disbursement_reconciliation"))
    assert resp.status_code == 200
    rows = {row["award"].pk: row for row in resp.context["rows"]}
    row = rows[award.pk]
    assert row["tranche_total"] == Decimal("1000")
    assert row["paid_disbursement_total"] == Decimal("400")
    assert row["flagged"] is True


@pytest.mark.django_db
def test_reconciliation_passes_when_totals_match(client, finance_user, applicant_user, institution):
    award = _award_for(applicant_user, institution, suffix="match")
    AwardTranche.objects.create(award=award, label="Tranche 1", amount=Decimal("1000"))
    donor = FundingSource.objects.create(name=f"Donor {award.pk}", code=f"donor-{award.pk}")
    budget = Budget.objects.create(award=award, name="Recon budget", funding_source=donor, currency=award.currency)
    DisbursementRequest.objects.create(
        budget=budget, amount=Decimal("1000"), status=DisbursementRequest.Status.PAID,
    )

    client.force_login(finance_user)
    resp = client.get(reverse("rims_finance:tranche_disbursement_reconciliation"))
    assert resp.status_code == 200
    rows = {row["award"].pk: row for row in resp.context["rows"]}
    assert rows[award.pk]["flagged"] is False
