from django.core.exceptions import ImproperlyConfigured
from django.db import migrations


class RenamePrimaryKey(migrations.RenameField):
    @property
    def reversible(self):
        return False

    def update_primary_key_relations(self, schema_editor, new_field):
        if schema_editor.connection.vendor == "sqlite":
            for rel in new_field.model._meta.related_objects:
                if not rel.many_to_many:
                    schema_editor._remake_table(rel.related_model)  # pylint: disable=protected-access

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        super().database_forwards(app_label, schema_editor, from_state, to_state)

        to_model = to_state.apps.get_model(app_label, self.model_name)
        new_field = to_model._meta.get_field(self.new_name)

        self.update_primary_key_relations(schema_editor, new_field)

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        raise NotImplementedError("You cannot reverse this operation")


# pylint: disable=W0613
def disable_check_constraints(apps, schema_editor):
    if schema_editor.connection.vendor == "sqlite":
        schema_editor.connection.check_constraints = lambda *args, **x: None


class Bs4ToBs5BasePageMigration(migrations.Migration):
    new_bases = None
    model_name = None
    old_fk = None
    new_fk = None
    new_field = None

    def apply(self, project_state, schema_editor, collect_sql=False):
        if not all([self.model_name, self.old_fk, self.new_fk, self.new_field]):
            raise ImproperlyConfigured(
                "Please fill out all values for: model_name, old_fk, new_fk, new_field. Read the readme for more explanation!"
            )

        model_identifier = (self.app_label, self.model_name.lower())
        model_state = project_state.models.get(model_identifier)

        new_state_fields = model_state.fields
        new_state_fields[self.new_fk] = self.new_field

        if not self.new_bases:
            self.new_bases = model_state.bases

        self.operations = [
            migrations.RunPython(disable_check_constraints, migrations.RunPython.noop),
            migrations.SeparateDatabaseAndState(
                state_operations=[
                    migrations.DeleteModel(self.model_name),
                    migrations.CreateModel(
                        name=self.model_name,
                        fields=new_state_fields.items(),
                        options=model_state.options,
                        bases=self.new_bases,
                    ),
                ],
                database_operations=[
                    RenamePrimaryKey(
                        model_name=self.model_name.lower(),
                        old_name=self.old_fk,
                        new_name=self.new_fk,
                    ),
                ],
            ),
        ]

        return super().apply(project_state, schema_editor, collect_sql)
