"""PRD §5.1 FRFA-CO026–029 — auto-flag FundingRecord as ready for programme
close-out when the last linked Award reaches CLOSED."""
from datetime import date, timedelta
from decimal import Decimal

import pytest
from django.utils import timezone

from apps.rims.grants.models import (
    Application,
    Award,
    FundingRecord,
    FundingRecordCloseout,
    GrantCall,
)
from apps.rims.grants.services import (
    award_application,
    shortlist_application,
    submit_application,
)


@pytest.fixture
def funding_record_with_two_awards(applicant_user, institution, db):
    from apps.core.authentication.models import Institution as _Inst
    from django.contrib.auth import get_user_model

    User = get_user_model()

    fr = FundingRecord.objects.create(
        title="FR close-out flag",
        amount=Decimal("2000"),
        start_date=date.today(),
        end_date=date.today() + timedelta(days=365),
    )
    call = GrantCall.objects.create(
        title="FR call",
        slug=f"fr-{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,
        funding_record=fr,
    )
    applicant2 = User.objects.create_user(email="a2-fr@example.com", password="pw")
    applicant2.institution = institution
    applicant2.save()

    awards = []
    for applicant in [applicant_user, applicant2]:
        app = Application.objects.create(call=call, applicant=applicant, 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="",
        )
        awards.append(Application.objects.get(pk=app.pk).award)
    return fr, awards


@pytest.mark.django_db
def test_funding_record_not_flagged_while_awards_still_active(funding_record_with_two_awards):
    fr, awards = funding_record_with_two_awards
    # Close one award only.
    awards[0].status = Award.Status.CLOSED
    awards[0].save()
    assert not FundingRecordCloseout.objects.filter(funding_record=fr).exists()


@pytest.mark.django_db
def test_funding_record_auto_flags_when_all_awards_closed(funding_record_with_two_awards):
    fr, awards = funding_record_with_two_awards
    awards[0].status = Award.Status.CLOSED
    awards[0].save()
    awards[1].status = Award.Status.CLOSED
    awards[1].save()
    closeout = FundingRecordCloseout.objects.get(funding_record=fr)
    assert closeout.status == FundingRecordCloseout.Status.READY


@pytest.mark.django_db
def test_signal_idempotent_on_repeated_save(funding_record_with_two_awards):
    fr, awards = funding_record_with_two_awards
    for a in awards:
        a.status = Award.Status.CLOSED
        a.save()
    # Second save of an already-CLOSED award should not create a duplicate row.
    for a in awards:
        a.save()
    assert FundingRecordCloseout.objects.filter(funding_record=fr).count() == 1
