from django.conf import settings
from django.db import migrations, models, transaction
import django.db.models.deletion
import uuid


def migrate_data(apps, schema_editor):
    # SQLite does not support altering constraints. However, we use it for tests only, and there's no data to migrate.
    if schema_editor.connection.vendor == 'sqlite':
        return

    def _sql_add_cascading_user_constraint(model_name, field_name):
        return f'ALTER TABLE desecapi_{model_name}' \
               f' ADD CONSTRAINT desecapi_{model_name}_{field_name}_id_update_cascade' \
               f' FOREIGN KEY (`{field_name}_id`) REFERENCES `desecapi_user` (`id`) ON UPDATE CASCADE'

    def _sql_drop_cascading_user_constraint(model_name, field_name):
        return f'ALTER TABLE desecapi_{model_name} DROP CONSTRAINT desecapi_{model_name}_{field_name}_id_update_cascade'

    # Add cascading foreign key constraints.
    # This has to be done after removing the regular constraints using migrations.AlterField. If done the other
    # way around, AlterField will drop the cascading constraint.
    schema_editor.execute(_sql_add_cascading_user_constraint('domain', 'owner')),
    schema_editor.execute(_sql_add_cascading_user_constraint('token', 'user')),

    # Repopulate user ID fields
    User = apps.get_model('desecapi', 'User')
    with transaction.atomic():
        for user in User.objects.all():
            User.objects.filter(email=user.email).update(id=uuid.uuid4().hex)

    # Remove cascading foreign key constraints
    schema_editor.execute(_sql_drop_cascading_user_constraint('domain', 'owner')),
    schema_editor.execute(_sql_drop_cascading_user_constraint('token', 'user')),


class Migration(migrations.Migration):
    dependencies = [
        ('desecapi', '0010_hash_tokens_and_switch_to_uuid'),
    ]

    operations = [
        # Switch to intermediate field type
        migrations.AlterField(
            model_name='user',
            name='id',
            field=models.CharField(default=uuid.uuid4, max_length=32, primary_key=True, serialize=False),
        ),

        # Remove regular foreign key constraints.
        # This is the migration Django generates when you set db_constraint=False on the model field.
        migrations.AlterField(
            model_name='domain',
            name='owner',
            field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.PROTECT,
                                    related_name='domains', to=settings.AUTH_USER_MODEL),
        ),
        migrations.AlterField(
            model_name='token',
            name='user',
            field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE,
                                    related_name='auth_tokens', to=settings.AUTH_USER_MODEL, verbose_name='User'),
        ),

        # Repopulate user IDs with random UUIDs
        migrations.RunPython(migrate_data, migrations.RunPython.noop, atomic=False),

        # Restore regular foreign key constraints
        migrations.AlterField(
            model_name='token',
            name='user',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='auth_tokens',
                                    to=settings.AUTH_USER_MODEL, verbose_name='User'),
        ),
        migrations.AlterField(
            model_name='domain',
            name='owner',
            field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='domains',
                                    to=settings.AUTH_USER_MODEL),
        ),

        # Switch to final field type
        migrations.AlterField(
            model_name='user',
            name='id',
            field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False),
        ),
    ]