"""Backfill ProjectFinance.fund from the owning project's sole fund.

Only unambiguous rows are filled: a project with exactly one fund has exactly
one candidate, so the attribution is a fact rather than a guess. Rows on a
co-funded project are left null deliberately — the correct fund is not
derivable there, and a wrong attribution would show one donor another donor's
spend, which is the bug this field exists to close.

Verified against the working database at authoring time: 120 of 120 rows sat on
single-fund projects, so nothing was left behind. That is not assumed here —
the query fills whatever is resolvable and skips the rest.
"""

from django.db import migrations
from django.db.models import Count, OuterRef, Subquery


def backfill_fund(apps, schema_editor):
    Project = apps.get_model("projects", "Project")
    ProjectFinance = apps.get_model("projects", "ProjectFinance")

    single_fund_projects = (
        Project.objects.annotate(fund_count=Count("funds", distinct=True))
        .filter(fund_count=1)
        .values_list("id", flat=True)
    )
    sole_fund = (
        apps.get_model("projects", "ProjectFund")
        .objects.filter(project_id=OuterRef("project_id"))
        .values("id")[:1]
    )
    ProjectFinance.objects.filter(
        fund__isnull=True, project_id__in=list(single_fund_projects),
    ).update(fund_id=Subquery(sole_fund))


def unset_fund(apps, schema_editor):
    """Reverse: clear the column. The field is nullable and was empty before
    this migration, so dropping the values restores the prior state exactly."""
    ProjectFinance = apps.get_model("projects", "ProjectFinance")
    ProjectFinance.objects.update(fund_id=None)


class Migration(migrations.Migration):

    dependencies = [
        ("projects", "0036_projectfinance_fund"),
    ]

    operations = [
        migrations.RunPython(backfill_fund, unset_fund),
    ]
