from typing import TYPE_CHECKING

from django.db import migrations

from ipfabric_netbox.utilities.endpoint import do_endpoint_change
from ipfabric_netbox.utilities.endpoint import EndpointRecord
from ipfabric_netbox.utilities.transform_map import do_change
from ipfabric_netbox.utilities.transform_map import FieldRecord
from ipfabric_netbox.utilities.transform_map import RelationshipRecord
from ipfabric_netbox.utilities.transform_map import TransformMapRecord

if TYPE_CHECKING:
    from django.apps import apps as apps_type
    from django.db.backends.base.schema import BaseDatabaseSchemaEditor

ENDPOINTS = (
    EndpointRecord(
        name="Default VSS Chassis Endpoint",
        description="",
        endpoint="/technology/platforms/vss/chassis",
    ),
)

TRANSFORM_MAP_CHANGES = (
    TransformMapRecord(
        source_endpoint="/technology/platforms/stack/members",
        target_model="dcim.virtualchassis",
        fields=(
            FieldRecord(
                source_field="master",
                target_field="name",
                old_template="",
                new_template="{% if object.master is defined and object.master %}{{ object.master }}{% else %}{{ object.hostname }}{% endif %}",
            ),
        ),
    ),
    TransformMapRecord(
        source_endpoint="/inventory/devices",
        target_model="dcim.device",
        fields=(
            FieldRecord(
                source_field="hostname",
                target_field="vc_position",
                old_template="{% if object.virtual_chassis %}{{ object.virtual_chassis.member }}{% else %}None{% endif %}",
                new_template="{% if object.virtual_chassis %}{% if object.virtual_chassis.member is defined and object.virtual_chassis.member %}{{ object.virtual_chassis.member }}{% else %}{{ object.virtual_chassis.chassisId }}{% endif %}{% else %}None{% endif %}",
            ),
        ),
        relationships=(
            RelationshipRecord(
                source_model="dcim.virtualchassis",
                target_field="virtual_chassis",
                old_template="{% if object.virtual_chassis %}{{ dcim.VirtualChassis.objects.filter(name=object.virtual_chassis.master).first().pk }}{% endif %}",
                new_template="{% if object.virtual_chassis %}{% if object.virtual_chassis.master is defined and object.virtual_chassis.master %}{{ dcim.VirtualChassis.objects.filter(name=object.virtual_chassis.master).first().pk }}{% else %}{{ dcim.VirtualChassis.objects.filter(name=object.virtual_chassis.hostname).first().pk }}{% endif %}{% endif %}",
            ),
        ),
    ),
)


def add_vss_chassis_endpoint(
    apps: "apps_type", schema_editor: "BaseDatabaseSchemaEditor"
):
    """Add VSS chassis endpoint."""
    do_endpoint_change(apps, schema_editor, ENDPOINTS, forward=True)


def remove_vss_chassis_endpoint(
    apps: "apps_type", schema_editor: "BaseDatabaseSchemaEditor"
):
    """Remove VSS chassis endpoint."""
    do_endpoint_change(apps, schema_editor, ENDPOINTS, forward=False)


def forward_transform_maps_change(
    apps: "apps_type", schema_editor: "BaseDatabaseSchemaEditor"
):
    """Replace old template with updated version."""
    do_change(apps, schema_editor, changes=TRANSFORM_MAP_CHANGES, forward=True)


def revert_transform_maps_change(
    apps: "apps_type", schema_editor: "BaseDatabaseSchemaEditor"
):
    """Revert template back to the previous exact template."""
    do_change(apps, schema_editor, changes=TRANSFORM_MAP_CHANGES, forward=False)


def add_vss_to_child_filter(
    apps: "apps_type", schema_editor: "BaseDatabaseSchemaEditor"
):
    """Add VSS chassis endpoint to Default Child Devices Filter idempotently."""
    IPFabricFilter = apps.get_model("ipfabric_netbox", "IPFabricFilter")
    IPFabricEndpoint = apps.get_model("ipfabric_netbox", "IPFabricEndpoint")

    # Get the filter
    try:
        child_filter = IPFabricFilter.objects.using(schema_editor.connection.alias).get(
            name="Default Child Devices Filter"
        )
    except IPFabricFilter.DoesNotExist:
        # Filter doesn't exist, nothing to update
        return

    # Get the VSS chassis endpoint
    try:
        vss_endpoint = IPFabricEndpoint.objects.using(
            schema_editor.connection.alias
        ).get(endpoint="/technology/platforms/vss/chassis")
    except IPFabricEndpoint.DoesNotExist:
        # Endpoint doesn't exist yet, skip (will be created by add_vss_chassis_endpoint)
        return

    # Add the endpoint to the filter if not already present
    if not child_filter.endpoints.filter(pk=vss_endpoint.pk).exists():
        child_filter.endpoints.add(vss_endpoint)


def remove_vss_from_child_filter(
    apps: "apps_type", schema_editor: "BaseDatabaseSchemaEditor"
):
    """Remove VSS chassis endpoint from Default Child Devices Filter."""
    IPFabricFilter = apps.get_model("ipfabric_netbox", "IPFabricFilter")
    IPFabricEndpoint = apps.get_model("ipfabric_netbox", "IPFabricEndpoint")

    # Get the filter
    try:
        child_filter = IPFabricFilter.objects.using(schema_editor.connection.alias).get(
            name="Default Child Devices Filter"
        )
    except IPFabricFilter.DoesNotExist:
        # Filter doesn't exist, nothing to update
        return

    # Get the VSS chassis endpoint
    try:
        vss_endpoint = IPFabricEndpoint.objects.using(
            schema_editor.connection.alias
        ).get(endpoint="/technology/platforms/vss/chassis")
    except IPFabricEndpoint.DoesNotExist:
        # Endpoint doesn't exist, nothing to remove
        return

    # Remove the endpoint from the filter if present
    if child_filter.endpoints.filter(pk=vss_endpoint.pk).exists():
        child_filter.endpoints.remove(vss_endpoint)


class Migration(migrations.Migration):
    dependencies = [
        ("ipfabric_netbox", "0024_finish_filters"),
    ]

    operations = [
        migrations.RunPython(
            add_vss_chassis_endpoint,
            remove_vss_chassis_endpoint,
        ),
        migrations.RunPython(
            forward_transform_maps_change,
            revert_transform_maps_change,
        ),
        migrations.RunPython(
            add_vss_to_child_filter,
            remove_vss_from_child_filter,
        ),
    ]
