"""PRD §5.1 FRFA-CO019 — donor close-out report generation + dispatch."""
from __future__ import annotations

from datetime import date, timedelta
from decimal import Decimal

from django.utils import timezone

from apps.rims.finance.models import FundingSource
from apps.rims.finance.services_analytics import donor_finance_packet


def generate_donor_closeout_pdf(
    donor: FundingSource,
    *,
    period_start: date | None = None,
    period_end: date | None = None,
) -> bytes:
    """Render the donor close-out report PDF for closed awards in the period.

    Returns the PDF bytes. The caller is responsible for delivery (the
    ``dispatch_donor_closeout_report`` Celery task handles email).
    """
    from apps.core.utils.pdf import render_pdf

    packet = donor_finance_packet(
        donor,
        period_start=period_start,
        period_end=period_end,
        closeout_only=True,
    )
    total_residual = Decimal("0")
    forced_rows = []
    for row in packet.rows:
        try:
            total_residual += Decimal(str(row.get("residual_returned") or "0"))
        except Exception:  # noqa: BLE001
            pass
        if row.get("forced_closure"):
            forced_rows.append(row)
    return render_pdf(
        "finance/donor_closeout_report.pdf.html",
        {
            "donor": donor,
            "packet": packet,
            "period_start": period_start,
            "period_end": period_end,
            "generated_at": timezone.now(),
            "total_residual": total_residual,
            "forced_rows": forced_rows,
        },
    )


def funding_sources_for_award(award) -> list[FundingSource]:
    """Distinct FundingSources that fund this award (via budget header or line)."""
    from apps.rims.finance.models import Budget, BudgetLine

    direct_ids = list(
        Budget.objects.filter(award=award, funding_source__isnull=False)
        .values_list("funding_source_id", flat=True)
    )
    line_ids = list(
        BudgetLine.objects.filter(budget__award=award, funding_source__isnull=False)
        .values_list("funding_source_id", flat=True)
    )
    ids = set(direct_ids) | set(line_ids)
    return list(FundingSource.objects.filter(pk__in=ids))


def _already_dispatched_recently(funding_record_id, donor_id: int) -> bool:
    """Idempotency: skip dispatch if a DONOR_CLOSEOUT_REPORT_SENT audit row
    was written for this (funding_record, donor) tuple in the last 7 days."""
    from apps.core.audit.models import AuditLog

    cutoff = timezone.now() - timedelta(days=7)
    return AuditLog.objects.filter(
        action="DONOR_CLOSEOUT_REPORT_SENT",
        target_app="rims_grants",
        target_model="FundingRecord",
        object_id=str(funding_record_id),
        timestamp__gte=cutoff,
        changes__donor_id=donor_id,
    ).exists()
