# Generated migration for adding custom field support to transform maps
from django.db import migrations


def add_custom_field_transform_fields(apps, schema_editor):
    """
    1. Add cf_ipfabric_source and cf_ipfabric_ingestion IPFabricTransformField entries
       to the default Site and Device transform maps so that existing installs pick up
       the new fields (new installs get them via build_transform_maps from transform_map.json).

    2. For any syncs that had update_custom_fields=False, create legacy group clones of the
       Site and Device transform maps that exclude all cf_* fields, and assign those groups
       to the affected syncs.
    """
    IPFabricSync = apps.get_model("ipfabric_netbox", "IPFabricSync")
    IPFabricTransformMap = apps.get_model("ipfabric_netbox", "IPFabricTransformMap")
    IPFabricTransformMapGroup = apps.get_model(
        "ipfabric_netbox", "IPFabricTransformMapGroup"
    )
    IPFabricTransformField = apps.get_model("ipfabric_netbox", "IPFabricTransformField")
    IPFabricRelationshipField = apps.get_model(
        "ipfabric_netbox", "IPFabricRelationshipField"
    )
    IPFabricEndpoint = apps.get_model("ipfabric_netbox", "IPFabricEndpoint")
    ContentType = apps.get_model("contenttypes", "ContentType")

    site_ct = ContentType.objects.filter(app_label="dcim", model="site").first()
    device_ct = ContentType.objects.filter(app_label="dcim", model="device").first()
    site_endpoint = IPFabricEndpoint.objects.filter(
        endpoint="/inventory/sites/overview"
    ).first()
    device_endpoint = IPFabricEndpoint.objects.filter(
        endpoint="/inventory/devices"
    ).first()

    # --- 1. Add CF transform fields to the default (ungrouped) maps ---

    cf_fields_by_map = [
        (
            site_ct,
            site_endpoint,
            [
                (
                    "siteName",
                    "cf_ipfabric_source",
                    "{{ object.ingestion.sync.snapshot_data.source.pk if object.ingestion else None }}",
                ),
                (
                    "siteName",
                    "cf_ipfabric_ingestion",
                    "{{ object.ingestion.pk if object.ingestion else None }}",
                ),
            ],
        ),
        (
            device_ct,
            device_endpoint,
            [
                (
                    "hostname",
                    "cf_ipfabric_source",
                    "{{ object.ingestion.sync.snapshot_data.source.pk if object.ingestion else None }}",
                ),
                (
                    "hostname",
                    "cf_ipfabric_ingestion",
                    "{{ object.ingestion.pk if object.ingestion else None }}",
                ),
            ],
        ),
    ]

    for ct, endpoint, fields in cf_fields_by_map:
        if not (ct and endpoint):
            continue
        default_map = IPFabricTransformMap.objects.filter(
            target_model=ct,
            source_endpoint=endpoint,
            group__isnull=True,
        ).first()
        if not default_map:
            continue
        for source_field, target_field, template in fields:
            IPFabricTransformField.objects.get_or_create(
                transform_map=default_map,
                target_field=target_field,
                defaults={
                    "source_field": source_field,
                    "coalesce": False,
                    "template": template,
                },
            )

    # --- 2. Legacy clones for syncs with update_custom_fields=False ---

    syncs_without_cf = IPFabricSync.objects.filter(update_custom_fields=False)

    if syncs_without_cf.exists():
        legacy_group, created = IPFabricTransformMapGroup.objects.get_or_create(
            name="Legacy (No Custom Fields)",
            defaults={
                "description": "Transform maps for syncs with custom field updates disabled. "
                "Excludes any custom field (cf_*) transform fields."
            },
        )

        for ct, endpoint in [(site_ct, site_endpoint), (device_ct, device_endpoint)]:
            if not (ct and endpoint):
                continue
            default_map = IPFabricTransformMap.objects.filter(
                target_model=ct,
                source_endpoint=endpoint,
                group__isnull=True,
            ).first()
            if not default_map:
                continue

            legacy_map = IPFabricTransformMap.objects.create(
                name=f"{default_map.name} (No CF)",
                source_endpoint=default_map.source_endpoint,
                target_model=default_map.target_model,
                group=legacy_group,
            )

            for field_map in default_map.field_maps.all():
                if not field_map.target_field.startswith("cf_"):
                    IPFabricTransformField.objects.create(
                        transform_map=legacy_map,
                        source_field=field_map.source_field,
                        target_field=field_map.target_field,
                        coalesce=field_map.coalesce,
                        template=field_map.template,
                    )

            for rel_map in default_map.relationship_maps.all():
                IPFabricRelationshipField.objects.create(
                    transform_map=legacy_map,
                    source_model=rel_map.source_model,
                    target_field=rel_map.target_field,
                    coalesce=rel_map.coalesce,
                    template=rel_map.template,
                )

        for sync in syncs_without_cf:
            parameters = sync.parameters or {}
            groups = parameters.get("groups", [])
            if legacy_group.pk not in groups:
                groups.insert(0, legacy_group.pk)
                parameters["groups"] = groups
                sync.parameters = parameters
                sync.save(update_fields=["parameters"])


def reverse_migration(apps, schema_editor):
    """Remove custom field transform fields and legacy group."""
    IPFabricTransformMapGroup = apps.get_model(
        "ipfabric_netbox", "IPFabricTransformMapGroup"
    )
    IPFabricTransformField = apps.get_model("ipfabric_netbox", "IPFabricTransformField")

    # Remove custom field transform fields
    IPFabricTransformField.objects.filter(target_field__startswith="cf_").delete()

    # Remove legacy group
    IPFabricTransformMapGroup.objects.filter(name="Legacy (No Custom Fields)").delete()


class Migration(migrations.Migration):
    dependencies = [
        ("ipfabric_netbox", "0031_merge_enhancements"),
    ]

    operations = [
        migrations.RunPython(add_custom_field_transform_fields, reverse_migration),
        migrations.RemoveField(
            model_name="ipfabricsync",
            name="update_custom_fields",
        ),
    ]
