from datetime import 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 approve_disbursement_request
from apps.rims.grants.models import Application, GrantCall
from apps.rims.grants.services import award_application, shortlist_application, submit_application
from apps.rims.projects.models import Milestone, Project


@pytest.mark.django_db
def test_disbursement_approval_blocked_when_milestone_not_accepted(applicant_user, institution):
    call = GrantCall.objects.create(
        title="Gate call",
        slug=f"gate-{int(timezone.now().timestamp())}",
        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, Decimal("900"), timezone.now().date() + timedelta(days=120), narrative="")
    award = Application.objects.get(pk=app.pk).award
    project = Project.objects.create(
        award=award,
        title="Gate project",
        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="Gate M1",
        due_date=timezone.now().date() + timedelta(days=10),
        status=Milestone.Status.SUBMITTED,
        report_due=True,
    )
    budget = Budget.objects.create(award=award, name="B1")
    BudgetLine.objects.create(budget=budget, label="L1", amount=Decimal("900"))
    req = DisbursementRequest.objects.create(
        budget=budget,
        milestone=milestone,
        amount=Decimal("100"),
        status=DisbursementRequest.Status.SUBMITTED,
    )
    with pytest.raises(ValidationError):
        approve_disbursement_request(req)
    milestone.status = Milestone.Status.ACCEPTED
    milestone.save(update_fields=["status"])
    approve_disbursement_request(req)
    req.refresh_from_db()
    assert req.status == DisbursementRequest.Status.APPROVED
