# Generated by Django 3.2.7 on 2022-03-24 16:37

import os
import os.path as osp

import django.db.models.deletion
from django.db import migrations, models


def migrate_sessionmaterial(apps, schema_editor):
    """Migrate the sessionmaterial to the materialcontent."""

    Material = apps.get_model("uploaded_material", "Material")
    SessionMaterial = apps.get_model("programme", "SessionMaterial")

    for sessionmaterial in SessionMaterial.objects.all():
        material = Material(
            id=sessionmaterial.id,
            date_created=sessionmaterial.date_created,
            external_url=sessionmaterial.external_url,
            last_modification_date=sessionmaterial.last_modification_date,
            name=sessionmaterial.name,
            upload_material=sessionmaterial.upload_material,
        )
        material.save()


def undo_migrate_sessionmaterial(apps, schema_editor):
    """Undo the migration"""
    Material = apps.get_model("uploaded_material", "Material")
    SessionMaterial = apps.get_model("programme", "SessionMaterial")

    for sessionmaterial in SessionMaterial.objects.all():
        try:
            material = Material.objects.get(id=sessionmaterial.id)
        except Material.DoesNotExist:
            continue

        sessionmaterial.date_created = material.date_created
        sessionmaterial.external_url = material.external_url
        sessionmaterial.last_modification_date = (
            material.last_modification_date
        )
        sessionmaterial.name = material.name
        sessionmaterial.upload_material = material.upload_material

        sessionmaterial.save()


def copy_id(apps, schema_editor):
    """Copy the id to legacy_id"""
    SessionMaterial = apps.get_model("programme", "SessionMaterial")

    for sessionmaterial in SessionMaterial.objects.all():
        sessionmaterial.legacy_id = sessionmaterial.id
        sessionmaterial.save()


def undo_copy_id(apps, schema_editor):
    """Revert the copy process"""
    SessionMaterial = apps.get_model("programme", "SessionMaterial")

    for sessionmaterial in SessionMaterial.objects.all():
        sessionmaterial.id = sessionmaterial.legacy_id
        sessionmaterial.save()


def update_pointer(apps, schema_editor):
    """Use the correct pointer for the session material."""

    Material = apps.get_model("uploaded_material", "Material")
    SessionMaterial = apps.get_model("programme", "SessionMaterial")

    for sessionmaterial in SessionMaterial.objects.all():
        material = Material.objects.get(id=sessionmaterial.id)
        sessionmaterial.material_ptr = material
        sessionmaterial.save()


def move_sessionmaterial(apps, schema_editor):
    """Undo the move of the session material."""
    Material = apps.get_model("uploaded_material", "Material")

    for material in Material.objects.filter(upload_material__isnull=False):
        old_path = material.upload_material.path
        name = material.upload_material.name
        filename = osp.basename(name)
        material.upload_material.name = osp.join(
            "media", "sessionmaterial", str(material.pk), filename
        )
        new_path = material.upload_material.path
        os.makedirs(osp.dirname(new_path), exist_ok=True)
        os.rename(old_path, new_path)
        material.save()


def undo_move_sessionmaterial(apps, schema_editor):
    """Undo the move of the session material."""

    SessionMaterial = apps.get_model("programme", "SessionMaterial")
    Material = apps.get_model("uploaded_material", "Material")

    for sessionmaterial in SessionMaterial.objects.filter(
        material_ptr__upload_material__isnull=False
    ):
        material = Material.objects.get(pk=sessionmaterial.material_ptr_id)
        old_path = material.upload_material.path
        name = material.upload_material.name
        if name.startswith("media"):
            new_name = osp.join(
                "sessionmaterial",
                str(sessionmaterial.session.pk),
                osp.basename(name),
            )
            material.upload_material.name = new_name
            new_path = material.upload_material.path
            os.makedirs(osp.dirname(new_path), exist_ok=True)
            os.rename(old_path, new_path)
            material.save()


class SeparateDataBaseAndBackwardState(migrations.SeparateDatabaseAndState):
    """Migration for different forward and backward operations."""

    def __init__(
        self,
        database_operations=None,
        state_operations=None,
        backward_database_operations=None,
    ):
        super().__init__(database_operations, state_operations)
        self.backward_database_operations = backward_database_operations or []

    def database_backwards(
        self, app_label, schema_editor, from_state, to_state
    ):
        # We calculate state separately in here since our state functions aren't useful
        for database_operation in reversed(self.backward_database_operations):
            to_state = from_state.clone()
            database_operation.state_forwards(app_label, to_state)
            database_operation.database_forwards(
                app_label, schema_editor, from_state, to_state
            )
            from_state = to_state


class Migration(migrations.Migration):

    dependencies = [
        ("uploaded_material", "0002_material_user"),
        ("programme", "0012_alter_sessionmaterial_name"),
    ]

    operations = [
        migrations.RunPython(
            migrate_sessionmaterial, undo_migrate_sessionmaterial
        ),
        migrations.RemoveField(
            model_name="sessionmaterial",
            name="date_created",
        ),
        migrations.RemoveField(
            model_name="sessionmaterial",
            name="external_url",
        ),
        migrations.RemoveField(
            model_name="sessionmaterial",
            name="last_modification_date",
        ),
        migrations.RemoveField(
            model_name="sessionmaterial",
            name="name",
        ),
        migrations.RemoveField(
            model_name="sessionmaterial",
            name="upload_material",
        ),
        SeparateDataBaseAndBackwardState(
            state_operations=[
                migrations.RemoveField(
                    model_name="sessionmaterial",
                    name="id",
                ),
                migrations.AddField(
                    model_name="sessionmaterial",
                    name="material_ptr",
                    field=models.OneToOneField(
                        auto_created=True,
                        default=1,
                        on_delete=django.db.models.deletion.CASCADE,
                        parent_link=True,
                        primary_key=True,
                        serialize=False,
                        to="uploaded_material.material",
                    ),
                    preserve_default=False,
                ),
            ],
            database_operations=[
                migrations.AddField(
                    model_name="sessionmaterial",
                    name="material_ptr",
                    field=models.OneToOneField(
                        auto_created=True,
                        null=True,
                        on_delete=django.db.models.deletion.CASCADE,
                        parent_link=True,
                        primary_key=False,
                        serialize=False,
                        to="uploaded_material.material",
                    ),
                    preserve_default=False,
                ),
                migrations.RunPython(update_pointer),
                migrations.RemoveField(
                    model_name="sessionmaterial",
                    name="id",
                ),
            ],
            backward_database_operations=[
                migrations.RunSQL(
                    """
                    BEGIN;
                    SELECT setval(pg_get_serial_sequence('"programme_sessionmaterial"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_sessionmaterial";
                    COMMIT;
                    """,
                    "",
                ),
                migrations.AlterField(
                    model_name="sessionmaterial",
                    name="id",
                    field=models.AutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                migrations.RemoveField(
                    model_name="sessionmaterial",
                    name="material_ptr",
                ),
                migrations.RunSQL(
                    "UPDATE programme_sessionmaterial "
                    "    SET id = material_ptr_id;"
                ),
                migrations.AddField(
                    model_name="sessionmaterial",
                    name="id",
                    field=models.IntegerField(
                        auto_created=True,
                        primary_key=False,
                        serialize=False,
                        default=1,
                        verbose_name="ID",
                    ),
                ),
            ],
        ),
        # reset indices
        migrations.RunSQL(
            """
            BEGIN;
            SELECT setval(pg_get_serial_sequence('"uploaded_material_material"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "uploaded_material_material";
            SELECT setval(pg_get_serial_sequence('"programme_affiliation"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_affiliation";
            SELECT setval(pg_get_serial_sequence('"programme_author"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_author";
            SELECT setval(pg_get_serial_sequence('"programme_presentationtype"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_presentationtype";
            SELECT setval(pg_get_serial_sequence('"programme_meetingroom"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_meetingroom";
            SELECT setval(pg_get_serial_sequence('"programme_session_conveners"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_session_conveners";
            SELECT setval(pg_get_serial_sequence('"programme_session_meeting_rooms"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_session_meeting_rooms";
            SELECT setval(pg_get_serial_sequence('"programme_session"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_session";
            SELECT setval(pg_get_serial_sequence('"programme_slot_organizing_members"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_slot_organizing_members";
            SELECT setval(pg_get_serial_sequence('"programme_slot"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_slot";
            SELECT setval(pg_get_serial_sequence('"programme_contribution"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_contribution";
            SELECT setval(pg_get_serial_sequence('"programme_contributingauthor_affiliation"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_contributingauthor_affiliation";
            SELECT setval(pg_get_serial_sequence('"programme_contributingauthor"','id'), coalesce(max("id"), 1), max("id") IS NOT null) FROM "programme_contributingauthor";
            COMMIT;
            """,
            "",
        ),
        # move files
        migrations.RunPython(move_sessionmaterial, undo_move_sessionmaterial),
    ]
