# Generated by Django 5.2 on 2025-01-05 11:58

import django.db.models.deletion
from django.db import migrations, models
from lamindb_setup.core.hashing import hash_dict

import lamindb.base.fields


def create_default_space(apps, schema_editor):
    Space = apps.get_model("lamindb", "Space")
    Space.objects.get_or_create(
        name="All",
        description="Every team & user with access to the instance has access.",
    )


def populate_hashes(apps, schema_editor):
    ParamValue = apps.get_model("lamindb", "ParamValue")

    # Process all existing records
    for param_value in ParamValue.objects.all():
        value = param_value.value
        # Check if value is a dict or list (complex JSON)
        if isinstance(value, dict):
            value_hash = hash_dict(value)
            param_value.hash = value_hash
            param_value.save()


class Migration(migrations.Migration):
    dependencies = [
        ("lamindb", "0070_lamindbv1_migrate_data"),
    ]

    operations = [
        # create Space model
        migrations.CreateModel(
            name="Space",
            fields=[
                ("id", models.SmallAutoField(primary_key=True, serialize=False)),
                ("name", models.CharField(db_index=True, max_length=100)),
                (
                    "description",
                    lamindb.base.fields.CharField(
                        blank=True, default=None, max_length=255, null=True
                    ),
                ),
                (
                    "created_at",
                    lamindb.base.fields.DateTimeField(
                        auto_now_add=True,
                        db_index=True,
                        default=django.utils.timezone.now,
                    ),
                ),
                (
                    "created_by",
                    lamindb.base.fields.ForeignKey(
                        blank=True,
                        default=None,
                        null=True,
                        on_delete=django.db.models.deletion.CASCADE,
                        related_name="+",
                        to="lamindb.user",
                    ),
                ),
            ],
            options={
                "abstract": False,
            },
        ),
        # populate the default space
        migrations.RunPython(create_default_space),
        # add space field to all models
        migrations.AddField(
            model_name="artifact",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="collection",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="feature",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="featureset",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="featurevalue",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="param",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="paramvalue",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="run",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="storage",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="transform",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="ulabel",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        migrations.AddField(
            model_name="user",
            name="space",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=1,
                on_delete=django.db.models.deletion.PROTECT,
                to="lamindb.space",
            ),
        ),
        # changes to transform
        migrations.RemoveField(
            model_name="transform",
            name="_source_code_artifact",
        ),
        # prepare removal of legacy description field
        migrations.RunSQL(
            sql="""
                UPDATE lamindb_transform
                SET name = name || ' ' || description
                WHERE description IS NOT NULL
                AND description != '';
            """
        ),
        migrations.RemoveField(
            model_name="transform",
            name="description",
        ),
        migrations.RenameField(
            model_name="transform",
            old_name="name",
            new_name="description",
        ),
        migrations.AlterField(
            model_name="transform",
            name="key",
            field=lamindb.base.fields.CharField(
                blank=True, db_index=True, default=None, max_length=255, null=True
            ),
        ),
        migrations.AlterField(
            model_name="transform",
            name="description",
            field=lamindb.base.fields.CharField(
                blank=True, db_index=True, default=None, max_length=255, null=True
            ),
        ),
        migrations.RunSQL(
            sql="""
                UPDATE lamindb_transform
                SET key = description
                WHERE key IS NULL and description IS NOT NULL;
            """
        ),
        # visibility -> _branch_code
        migrations.RenameField(
            model_name="collection",
            old_name="name",
            new_name="key",
        ),
        migrations.AlterField(
            model_name="collection",
            name="key",
            field=lamindb.base.fields.CharField(
                blank=True, db_index=True, default=None, max_length=255
            ),
        ),
        # visibility -> _branch_code
        migrations.RenameField(
            model_name="artifact",
            old_name="visibility",
            new_name="_branch_code",
        ),
        migrations.RenameField(
            model_name="collection",
            old_name="visibility",
            new_name="_branch_code",
        ),
        migrations.AlterField(
            model_name="artifact",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        migrations.AlterField(
            model_name="collection",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        migrations.AddField(
            model_name="feature",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        migrations.AddField(
            model_name="featureset",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        migrations.AddField(
            model_name="param",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        migrations.AddField(
            model_name="run",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        migrations.AddField(
            model_name="storage",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        migrations.AddField(
            model_name="transform",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        migrations.AddField(
            model_name="ulabel",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        migrations.AddField(
            model_name="user",
            name="_branch_code",
            field=models.SmallIntegerField(db_index=True, default=1, db_default=1),
        ),
        # fix dtype values
        migrations.RunSQL(
            sql="""
                UPDATE lamindb_feature
                SET dtype = 'num'
                WHERE dtype = 'number'
            """
        ),
        migrations.RunSQL(
            sql="""
                UPDATE lamindb_featureset
                SET dtype = 'num'
                WHERE dtype = 'number'
            """
        ),
        # an aux field on SQLRecord
        migrations.AddField(
            model_name="artifact",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.AddField(
            model_name="collection",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.AddField(
            model_name="feature",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.AddField(
            model_name="featureset",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.AddField(
            model_name="param",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.AddField(
            model_name="run",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.AddField(
            model_name="storage",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.AddField(
            model_name="transform",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.AddField(
            model_name="ulabel",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.AddField(
            model_name="user",
            name="aux",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        migrations.RenameField(
            model_name="run",
            old_name="is_consecutive",
            new_name="_is_consecutive",
        ),
        migrations.AddField(
            model_name="run",
            name="_status_code",
            field=models.SmallIntegerField(db_index=True, default=0),
        ),
        migrations.AddField(
            model_name="transform",
            name="_template",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=None,
                null=True,
                on_delete=django.db.models.deletion.PROTECT,
                related_name="_derived_from",
                to="lamindb.transform",
            ),
        ),
        migrations.RenameField(
            model_name="artifact",
            old_name="type",
            new_name="kind",
        ),
        migrations.RenameField(
            model_name="artifact",
            old_name="_accessor",
            new_name="otype",
        ),
        migrations.AddField(
            model_name="run",
            name="_logfile",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=None,
                null=True,
                on_delete=django.db.models.deletion.PROTECT,
                related_name="_logfile_of",
                to="lamindb.artifact",
            ),
        ),
        # unique constraint on hash
        migrations.AddField(
            model_name="featurevalue",
            name="hash",
            field=lamindb.base.fields.CharField(
                blank=True, db_index=True, default=None, max_length=22, null=True
            ),
        ),
        migrations.AddField(
            model_name="paramvalue",
            name="hash",
            field=lamindb.base.fields.CharField(
                blank=True, db_index=True, default=None, max_length=22, null=True
            ),
        ),
        migrations.RunPython(populate_hashes),
        migrations.AddConstraint(
            model_name="featurevalue",
            constraint=models.UniqueConstraint(
                condition=models.Q(("hash__isnull", True)),
                fields=("feature", "value"),
                name="unique_simple_feature_value",
            ),
        ),
        migrations.AddConstraint(
            model_name="featurevalue",
            constraint=models.UniqueConstraint(
                condition=models.Q(("hash__isnull", False)),
                fields=("feature", "hash"),
                name="unique_complex_feature_value",
            ),
        ),
        migrations.AddConstraint(
            model_name="paramvalue",
            constraint=models.UniqueConstraint(
                condition=models.Q(("hash__isnull", True)),
                fields=("param", "value"),
                name="unique_simple_param_value",
            ),
        ),
        migrations.AddConstraint(
            model_name="paramvalue",
            constraint=models.UniqueConstraint(
                condition=models.Q(("hash__isnull", False)),
                fields=("param", "hash"),
                name="unique_complex_param_value",
            ),
        ),
        # add _curator field
        migrations.AddField(
            model_name="artifact",
            name="_curator",
            field=models.JSONField(default=None, db_default=None, null=True),
        ),
        # add _expect_many fields
        migrations.AddField(
            model_name="feature",
            name="_expect_many",
            field=models.BooleanField(default=True, db_default=True),
        ),
        migrations.AddField(
            model_name="param",
            name="_expect_many",
            field=models.BooleanField(default=False, db_default=False),
        ),
        # remove transform field
        migrations.RemoveField(
            model_name="artifact",
            name="transform",
        ),
        migrations.RemoveField(
            model_name="collection",
            name="transform",
        ),
        # richer link tables
        migrations.CreateModel(
            name="TransformULabel",
            fields=[
                (
                    "created_at",
                    lamindb.base.fields.DateTimeField(auto_now_add=True, db_index=True),
                ),
                ("id", models.BigAutoField(primary_key=True, serialize=False)),
                (
                    "created_by",
                    lamindb.base.fields.ForeignKey(
                        blank=True,
                        default=lamindb.base.users.current_user_id,
                        on_delete=django.db.models.deletion.PROTECT,
                        related_name="+",
                        to="lamindb.user",
                    ),
                ),
                (
                    "run",
                    lamindb.base.fields.ForeignKey(
                        blank=True,
                        default=lamindb.models.current_run,
                        null=True,
                        on_delete=django.db.models.deletion.PROTECT,
                        related_name="+",
                        to="lamindb.run",
                    ),
                ),
                (
                    "transform",
                    lamindb.base.fields.ForeignKey(
                        blank=True,
                        on_delete=django.db.models.deletion.CASCADE,
                        related_name="links_ulabel",
                        to="lamindb.transform",
                    ),
                ),
                (
                    "ulabel",
                    lamindb.base.fields.ForeignKey(
                        blank=True,
                        on_delete=django.db.models.deletion.PROTECT,
                        related_name="links_transform",
                        to="lamindb.ulabel",
                    ),
                ),
            ],
            options={
                "unique_together": {("transform", "ulabel")},
            },
            bases=(lamindb.models.IsLink, models.Model),
        ),
        migrations.RunSQL(
            sql="""
            INSERT INTO lamindb_transformulabel (transform_id, ulabel_id, created_at, created_by_id)
            SELECT
                transform_id,
                ulabel_id,
                CURRENT_TIMESTAMP,  -- Sets current timestamp for created_at
                1  -- Sets default user ID 1 for created_by_id
            FROM lamindb_transform_ulabels;
            """
        ),
        migrations.RemoveField(
            model_name="transform",
            name="ulabels",
        ),
        migrations.AddField(
            model_name="transform",
            name="ulabels",
            field=models.ManyToManyField(
                to="lamindb.ulabel",
                through="lamindb.TransformULabel",
                related_name="transforms",
            ),
        ),
        migrations.AddField(
            model_name="artifactparamvalue",
            name="created_at",
            field=lamindb.base.fields.DateTimeField(
                auto_now_add=True, db_index=True, default=django.utils.timezone.now
            ),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name="artifactparamvalue",
            name="created_by",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=lamindb.base.users.current_user_id,
                on_delete=django.db.models.deletion.PROTECT,
                related_name="+",
                to="lamindb.user",
            ),
        ),
        migrations.AddField(
            model_name="artifactparamvalue",
            name="run",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=lamindb.models.current_run,
                null=True,
                on_delete=django.db.models.deletion.PROTECT,
                related_name="+",
                to="lamindb.run",
            ),
        ),
        migrations.AddField(
            model_name="runparamvalue",
            name="created_at",
            field=lamindb.base.fields.DateTimeField(
                auto_now_add=True, db_index=True, default=django.utils.timezone.now
            ),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name="runparamvalue",
            name="created_by",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=lamindb.base.users.current_user_id,
                on_delete=django.db.models.deletion.PROTECT,
                related_name="+",
                to="lamindb.user",
            ),
        ),
        migrations.AddField(
            model_name="ulabel",
            name="is_concept",
            field=lamindb.base.fields.BooleanField(
                blank=True,
                default=False,
                db_default=False,
            ),
        ),
        migrations.RenameField(
            model_name="run",
            old_name="parent",
            new_name="initiated_by_run",
        ),
        migrations.AlterField(
            model_name="run",
            name="initiated_by_run",
            field=lamindb.base.fields.ForeignKey(
                blank=True,
                default=None,
                null=True,
                on_delete=django.db.models.deletion.CASCADE,
                related_name="initiated_runs",
                to="lamindb.run",
            ),
        ),
        # create and set _overwrite_versions
        migrations.AddField(
            model_name="artifact",
            name="_overwrite_versions",
            field=lamindb.base.fields.BooleanField(blank=True, default=None, null=True),
        ),
        migrations.RunSQL(
            sql="""
            UPDATE lamindb_artifact
            SET _overwrite_versions = CASE
                WHEN n_objects IS NOT NULL THEN TRUE
                ELSE FALSE
            END;
            """
        ),
        # rename n_files to n_objects
        migrations.RenameField(
            model_name="artifact",
            old_name="n_objects",
            new_name="n_files",
        ),
        # let feature value and paramvalue inherit from SQLRecord
        migrations.AddField(
            model_name="featurevalue",
            name="_branch_code",
            field=models.SmallIntegerField(db_default=1, db_index=True, default=1),
        ),
        migrations.AddField(
            model_name="featurevalue",
            name="aux",
            field=models.JSONField(db_default=None, default=None, null=True),
        ),
        migrations.AddField(
            model_name="paramvalue",
            name="_branch_code",
            field=models.SmallIntegerField(db_default=1, db_index=True, default=1),
        ),
        migrations.AddField(
            model_name="paramvalue",
            name="aux",
            field=models.JSONField(db_default=None, default=None, null=True),
        ),
        migrations.AddField(
            model_name="run",
            name="name",
            field=lamindb.base.fields.CharField(
                blank=True, default=None, max_length=150, null=True
            ),
        ),
        migrations.AlterField(
            model_name="space",
            name="created_at",
            field=lamindb.base.fields.DateTimeField(auto_now_add=True, db_index=True),
        ),
        migrations.AddField(
            model_name="param",
            name="type",
            field=lamindb.base.fields.CharField(
                blank=True, db_index=True, default=None, max_length=100, null=True
            ),
        ),
        migrations.AddField(
            model_name="feature",
            name="type",
            field=lamindb.base.fields.CharField(
                blank=True, db_index=True, default=None, max_length=100, null=True
            ),
        ),
        migrations.RemoveField(
            model_name="feature",
            name="_previous_runs",
        ),
        migrations.RemoveField(
            model_name="param",
            name="_previous_runs",
        ),
        migrations.RemoveField(
            model_name="storage",
            name="_previous_runs",
        ),
        migrations.RemoveField(
            model_name="ulabel",
            name="_previous_runs",
        ),
        migrations.AlterField(
            model_name="artifact",
            name="_overwrite_versions",
            field=lamindb.base.fields.BooleanField(blank=True, default=None),
        ),
    ]
