"""PRD §5.1 FRFA-CO005–010 — FinalNarrativeReport + FinalFinancialReport FSMs."""
from datetime import date, timedelta
from decimal import Decimal

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

from apps.rims.grants.closeout_helpers import (
    accept_financial_report,
    accept_narrative_report,
    get_or_create_closeout_record,
    raise_financial_queries,
    request_financial_revision,
    request_narrative_revision,
)
from apps.rims.grants.models import (
    Application,
    FinalFinancialReport,
    FinalNarrativeReport,
    GrantCall,
)
from apps.rims.grants.services import (
    award_application,
    shortlist_application,
    submit_application,
)


@pytest.fixture
def closeout_record(applicant_user, institution):
    call = GrantCall.objects.create(
        title="Report FSM call",
        slug=f"rpt-{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"), date.today() + timedelta(days=180), narrative="")
    award = Application.objects.get(pk=app.pk).award
    return get_or_create_closeout_record(award)


@pytest.mark.django_db
def test_accept_narrative_report_transitions_to_accepted(
    closeout_record, grants_manager_user
):
    report = FinalNarrativeReport.objects.create(closeout=closeout_record, notes="Final")
    accept_narrative_report(report, actor=grants_manager_user, comment="Thanks")
    fresh = FinalNarrativeReport.objects.get(pk=report.pk)
    assert fresh.status == FinalNarrativeReport.Status.ACCEPTED
    assert fresh.reviewed_at is not None
    assert fresh.reviewed_by_id == grants_manager_user.pk
    assert "Thanks" in fresh.review_comment


@pytest.mark.django_db
def test_narrative_revision_requires_comment(closeout_record, grants_manager_user):
    report = FinalNarrativeReport.objects.create(closeout=closeout_record, notes="")
    with pytest.raises(ValidationError):
        request_narrative_revision(report, comment="   ", actor=grants_manager_user)


@pytest.mark.django_db
def test_narrative_revision_then_resubmit_cycle(closeout_record, grants_manager_user):
    report = FinalNarrativeReport.objects.create(closeout=closeout_record, notes="")
    request_narrative_revision(report, comment="Please expand section 3", actor=grants_manager_user)
    report = FinalNarrativeReport.objects.get(pk=report.pk)
    assert report.status == FinalNarrativeReport.Status.REVISION_REQUIRED
    report.resubmit()
    report.save(update_fields=["status", "reviewed_at"])
    assert FinalNarrativeReport.objects.get(pk=report.pk).status == FinalNarrativeReport.Status.SUBMITTED


@pytest.mark.django_db
def test_financial_report_accept_and_queries(closeout_record, finance_user):
    report = FinalFinancialReport.objects.create(closeout=closeout_record, notes="Final financial")
    raise_financial_queries(report, queries="Please explain variance on line 4", actor=finance_user)
    report = FinalFinancialReport.objects.get(pk=report.pk)
    assert report.status == FinalFinancialReport.Status.QUERIES_RAISED
    # Awardee resubmits.
    report.resubmit()
    report.save(update_fields=["status", "reviewed_at"])
    report = FinalFinancialReport.objects.get(pk=report.pk)
    assert report.status == FinalFinancialReport.Status.SUBMITTED
    accept_financial_report(report, actor=finance_user)
    assert (
        FinalFinancialReport.objects.get(pk=report.pk).status
        == FinalFinancialReport.Status.ACCEPTED
    )


@pytest.mark.django_db
def test_financial_report_queries_require_text(closeout_record, finance_user):
    report = FinalFinancialReport.objects.create(closeout=closeout_record, notes="")
    with pytest.raises(ValidationError):
        raise_financial_queries(report, queries="", actor=finance_user)


@pytest.mark.django_db
def test_accepted_narrative_cannot_be_re_reviewed(closeout_record, grants_manager_user):
    report = FinalNarrativeReport.objects.create(closeout=closeout_record, notes="")
    accept_narrative_report(report, actor=grants_manager_user)
    report = FinalNarrativeReport.objects.get(pk=report.pk)
    with pytest.raises(TransitionNotAllowed):
        report.request_revision()
