"""PRD §5.4 FRFM012/013/015 — approval workflow configuration."""
from __future__ import annotations

from decimal import Decimal
from unittest.mock import patch

import pytest
from django.core.exceptions import ValidationError as DjangoValidationError
from django.utils import timezone
from datetime import timedelta

from apps.core.audit.models import AuditLog
from apps.core.audit.tasks import persist_audit_log
from apps.rims.finance.models import BudgetApprovalWorkflow, FundingSource
from apps.rims.finance.services import configure_budget_workflow
from apps.rims.grants.models import Application, Award, GrantCall


@pytest.fixture(autouse=True)
def _sync_audit():
    with patch("apps.core.audit.tasks.write_audit_log.delay", side_effect=lambda **kw: persist_audit_log(**kw)):
        with patch(
            "apps.core.audit.mixins.transaction.on_commit",
            side_effect=lambda fn: fn(),
        ):
            yield


def _award(applicant_user, institution):
    call = GrantCall.objects.create(
        title=f"6C-wf call {timezone.now().timestamp()}",
        slug=f"6c-wf-{int(timezone.now().timestamp() * 1000) % 10_000_000}",
        call_type="grant",
        opens_at=timezone.now() - timedelta(days=200),
        closes_at=timezone.now() + timedelta(days=10),
        status=GrantCall.Status.PUBLISHED,
    )
    app = Application.objects.create(call=call, applicant=applicant_user, institution=institution)
    return Award.objects.create(
        application=app,
        amount=Decimal("50000"),
        currency="USD",
        awarded_at=timezone.now(),
        project_end_date=timezone.now().date() + timedelta(days=365),
    )


@pytest.mark.django_db
def test_configure_workflow_with_award_emits_audit(applicant_user, institution, finance_user):
    award = _award(applicant_user, institution)
    wf = configure_budget_workflow(
        actor=finance_user,
        award=award,
        approval_mode=BudgetApprovalWorkflow.Mode.LINE,
        threshold_amount=Decimal("10000"),
        required_tiers=["finance_manager", "program_coordinator"],
    )
    assert wf.pk
    assert wf.award_id == award.pk
    assert wf.required_tiers == ["finance_manager", "program_coordinator"]
    assert AuditLog.objects.filter(action="BUDGET_APPROVAL_WORKFLOW_CONFIGURED").exists()


@pytest.mark.django_db
def test_configure_workflow_with_funding_source(finance_user):
    fs = FundingSource.objects.create(name="6C Donor", code="6c-donor")
    wf = configure_budget_workflow(
        actor=finance_user,
        funding_source=fs,
        approval_mode=BudgetApprovalWorkflow.Mode.TOTAL,
    )
    assert wf.funding_source_id == fs.pk


@pytest.mark.django_db
def test_configure_workflow_rejects_missing_scope(finance_user):
    with pytest.raises(DjangoValidationError):
        configure_budget_workflow(actor=finance_user)
