"""PRD §5.1 FRFA-AA015-018 — disbursement→AwardTranche bridge.

The UI-reachable disbursement path is DisbursementRequest → DisbursementExecution
(this app). AwardTranche (in apps.rims.grants) has its own promote-on-accept
signal chain via MilestoneEvidence, but is otherwise dead in production — no
view ever writes AwardTranche.disbursed_at. This test confirms the pragmatic
bridge added to save_execution_plan(): executing a milestone-linked
DisbursementRequest mirrors the paid state onto the matching AwardTranche
(matched via the explicit AwardTranche.milestone FK) when one exists, and is a
no-op (not an error) when it doesn't.
"""
from datetime import timedelta
from decimal import Decimal

import pytest
from django.utils import timezone

from apps.rims.finance.models import Budget, BudgetLine, DisbursementExecution, DisbursementRequest
from apps.rims.finance.services import approve_disbursement_request, save_execution_plan
from apps.rims.grants.models import Application, AwardTranche, GrantCall
from apps.rims.grants.services import award_application, shortlist_application, submit_application
from apps.rims.projects.models import Milestone, Project


def _award_with_milestone(applicant_user, institution, *, suffix, amount=Decimal("900")):
    call = GrantCall.objects.create(
        title=f"Bridge call {suffix}",
        slug=f"bridge-{suffix}-{int(timezone.now().timestamp() * 1000) % 10_000_000}",
        opens_at=timezone.now() - timedelta(days=1),
        closes_at=timezone.now() + timedelta(days=20),
        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, amount, timezone.now().date() + timedelta(days=120), narrative="")
    award = Application.objects.get(pk=app.pk).award
    project = Project.objects.create(
        award=award,
        title=f"Bridge project {suffix}",
        summary="",
        start_date=timezone.now().date(),
        end_date=timezone.now().date() + timedelta(days=90),
        status=Project.Status.ACTIVE,
    )
    milestone = Milestone.objects.create(
        project=project,
        name="Bridge M1",
        due_date=timezone.now().date() + timedelta(days=10),
        status=Milestone.Status.ACCEPTED,
        report_due=True,
    )
    budget = Budget.objects.create(award=award, name="Bridge budget")
    BudgetLine.objects.create(budget=budget, label="L1", amount=amount)
    return award, milestone, budget


def _approved_request(budget, milestone, amount):
    req = DisbursementRequest.objects.create(
        budget=budget,
        milestone=milestone,
        amount=amount,
        status=DisbursementRequest.Status.SUBMITTED,
    )
    approve_disbursement_request(req)
    req.refresh_from_db()
    return req


@pytest.mark.django_db
def test_executing_disbursement_updates_matching_tranche(applicant_user, institution):
    award, milestone, budget = _award_with_milestone(applicant_user, institution, suffix="match")
    tranche = AwardTranche.objects.create(
        award=award,
        milestone=milestone,
        label="Milestone 1 tranche",
        amount=Decimal("100"),
    )
    req = _approved_request(budget, milestone, Decimal("100"))

    save_execution_plan(
        req,
        status=DisbursementExecution.Status.EXECUTED,
        payment_method="bank_transfer",
        execution_reference="TXN-BRIDGE-001",
    )

    tranche.refresh_from_db()
    assert tranche.status == AwardTranche.Status.DISBURSED
    assert tranche.disbursed_at is not None
    assert tranche.payment_reference == "TXN-BRIDGE-001"


@pytest.mark.django_db
def test_executing_disbursement_without_matching_tranche_does_not_error(applicant_user, institution):
    award, milestone, budget = _award_with_milestone(applicant_user, institution, suffix="nomatch")
    # No AwardTranche created at all for this award — this award is operated
    # entirely through the DisbursementRequest system.
    req = _approved_request(budget, milestone, Decimal("100"))

    execution = save_execution_plan(
        req,
        status=DisbursementExecution.Status.EXECUTED,
        payment_method="bank_transfer",
        execution_reference="TXN-BRIDGE-002",
    )

    assert execution.status == DisbursementExecution.Status.EXECUTED
    req.refresh_from_db()
    assert req.status == DisbursementRequest.Status.PAID
    assert not AwardTranche.objects.filter(award=award).exists()


@pytest.mark.django_db
def test_executing_disbursement_with_no_milestone_link_is_a_noop_for_tranches(applicant_user, institution):
    award, milestone, budget = _award_with_milestone(applicant_user, institution, suffix="nolink")
    tranche = AwardTranche.objects.create(
        award=award,
        milestone=milestone,
        label="Milestone 1 tranche",
        amount=Decimal("100"),
    )
    # Request has no milestone attached — bridge must not touch any tranche.
    req = DisbursementRequest.objects.create(
        budget=budget,
        milestone=None,
        amount=Decimal("50"),
        status=DisbursementRequest.Status.SUBMITTED,
    )
    approve_disbursement_request(req)
    req.refresh_from_db()

    save_execution_plan(
        req,
        status=DisbursementExecution.Status.EXECUTED,
        payment_method="bank_transfer",
        execution_reference="TXN-BRIDGE-003",
    )

    tranche.refresh_from_db()
    assert tranche.status == AwardTranche.Status.PLANNED
    assert tranche.disbursed_at is None
