# Generated by Django 5.2.7 on 2026-02-20 12:03

from django.db import migrations


def get_additional_information(scenario):
    from envipy_additional_information import registry
    from envipy_additional_information.parsers import TypeOfAerationParser

    for k, vals in scenario.additional_information.items():
        if k == "enzyme":
            continue

        if k == "SpikeConentration":
            k = "SpikeConcentration"

        if k == "AerationType":
            k = "TypeOfAeration"

        for v in vals:
            # Per default additional fields are ignored
            MAPPING = {c.__name__: c for c in registry.list_models().values()}
            try:
                inst = MAPPING[k](**v)
            except Exception:
                if k == "TypeOfAeration":
                    toa = TypeOfAerationParser()
                    inst = toa.from_string(v["type"])

            # Add uuid to uniquely identify objects for manipulation
            if "uuid" in v:
                inst.__dict__["uuid"] = v["uuid"]

            yield inst


def forward_func(apps, schema_editor):
    Scenario = apps.get_model("epdb", "Scenario")
    ContentType = apps.get_model("contenttypes", "ContentType")
    AdditionalInformation = apps.get_model("epdb", "AdditionalInformation")

    bulk = []
    related = []
    ctype = {o.model: o for o in ContentType.objects.all()}
    parents = Scenario.objects.prefetch_related(
        "compound_set",
        "compoundstructure_set",
        "reaction_set",
        "rule_set",
        "pathway_set",
        "node_set",
        "edge_set",
    ).filter(parent__isnull=True)

    for i, scenario in enumerate(parents):
        print(f"{i + 1}/{len(parents)}", end="\r")
        if scenario.parent is not None:
            related.append(scenario.parent)
            continue

        for ai in get_additional_information(scenario):
            bulk.append(
                AdditionalInformation(
                    package=scenario.package,
                    scenario=scenario,
                    type=ai.__class__.__name__,
                    data=ai.model_dump(mode="json"),
                )
            )

    print("\n", len(bulk))

    related = Scenario.objects.prefetch_related(
        "compound_set",
        "compoundstructure_set",
        "reaction_set",
        "rule_set",
        "pathway_set",
        "node_set",
        "edge_set",
    ).filter(parent__isnull=False)

    for i, scenario in enumerate(related):
        print(f"{i + 1}/{len(related)}", end="\r")
        parent = scenario.parent
        # Check to which objects this scenario is attached to
        for ai in get_additional_information(scenario):
            rel_objs = [
                "compound",
                "compoundstructure",
                "reaction",
                "rule",
                "pathway",
                "node",
                "edge",
            ]
            for rel_obj in rel_objs:
                for o in getattr(scenario, f"{rel_obj}_set").all():
                    bulk.append(
                        AdditionalInformation(
                            package=scenario.package,
                            scenario=parent,
                            type=ai.__class__.__name__,
                            data=ai.model_dump(mode="json"),
                            content_type=ctype[rel_obj],
                            object_id=o.pk,
                        )
                    )

    print("Start creating additional information objects...")
    AdditionalInformation.objects.bulk_create(bulk)
    print("Done!")
    print(len(bulk))

    Scenario.objects.filter(parent__isnull=False).delete()
    # Call ai save to fix urls
    ais = AdditionalInformation.objects.all()
    total = ais.count()

    for i, ai in enumerate(ais):
        print(f"{i + 1}/{total}", end="\r")
        ai.save()


class Migration(migrations.Migration):
    dependencies = [
        ("epdb", "0017_additionalinformation"),
    ]

    operations = [
        migrations.RunPython(forward_func, reverse_code=migrations.RunPython.noop),
    ]
