# Generated by Django 3.2.25 on 2024-05-29 15:35
import hashlib

from django.db import connection, migrations


class Migration(migrations.Migration):

    dependencies = [
        ("NEMO", "0080_version_6_0_0"),
    ]

    def check_nemo_6_0_0_oracle_long_names(apps, schema_editor):
        rename_table_sql = "ALTER TABLE %s RENAME TO %s;"
        rename_column_sql = "ALTER TABLE %s RENAME COLUMN %s to %s;"
        max_name_length = connection.ops.max_name_length()

        table_renames = []
        column_renames = []

        if getattr(connection, "vendor", "") == "oracle":
            print("We have an ORACLE db, we need to fix tables for django 4.0")
            with connection.cursor() as cursor:
                table_list = connection.introspection.get_table_list(cursor)

                for _model in apps.get_models(include_auto_created=True):
                    # Table names.
                    db_table = _model._meta.db_table
                    new_quoted_name = connection.ops.quote_name(db_table)
                    old_quoted_name = new_quoted_name
                    if len(db_table) > max_name_length:
                        if new_quoted_name.lower() not in table_list:
                            old_quoted_name = old_quote_name(_model._meta.db_table, max_name_length)
                            table_renames.append(rename_table_sql % (old_quoted_name, new_quoted_name))

                    # Column names:
                    column_list = connection.introspection.get_table_description(cursor, strip_quotes(old_quoted_name))
                    for field in _model._meta.local_fields:
                        if len(field.column) > max_name_length:
                            field_quoted_name = connection.ops.quote_name(field.column)
                            if field_quoted_name.lower() not in column_list:
                                column_renames.append(
                                    rename_column_sql
                                    % (
                                        new_quoted_name,
                                        old_quote_name(field.column, max_name_length),
                                        field_quoted_name,
                                    )
                                )

                sql_queries = table_renames + column_renames
                if not sql_queries:
                    print("No changes needed")
                else:
                    with connection.cursor() as cursor:
                        for sql in table_renames + column_renames:
                            print("executing: " + sql)
                            cursor.execute(sql)
                            print("done")

    def check_nemo_6_0_0_oracle_long_names_reverse(apps, schema_editor):
        rename_table_sql = "ALTER TABLE %s RENAME TO %s;"
        rename_column_sql = "ALTER TABLE %s RENAME COLUMN %s to %s;"
        max_name_length = connection.ops.max_name_length()

        table_renames = []
        column_renames = []

        if getattr(connection, "vendor", "") == "oracle":
            print("We have an ORACLE db, we need to fix tables for django 4.0")
            with connection.cursor() as cursor:
                table_list = connection.introspection.get_table_list(cursor)

                for _model in apps.get_models(include_auto_created=True):
                    # Table names.
                    db_table = _model._meta.db_table
                    new_quoted_name = connection.ops.quote_name(db_table)
                    if len(db_table) > max_name_length:
                        old_quoted_name = old_quote_name(_model._meta.db_table, max_name_length)
                        if old_quoted_name.lower() not in table_list:
                            table_renames.append(rename_table_sql % (new_quoted_name, old_quoted_name))

                    # Column names:
                    column_list = connection.introspection.get_table_description(cursor, strip_quotes(new_quoted_name))
                    for field in _model._meta.local_fields:
                        if len(field.column) > max_name_length:
                            old_quoted_name = old_quote_name(field.column, max_name_length)
                            if old_quoted_name.lower() not in column_list:
                                field_quoted_name = connection.ops.quote_name(field.column)
                                column_renames.append(
                                    rename_column_sql
                                    % (
                                        new_quoted_name,
                                        field_quoted_name,
                                        old_quote_name(field.column, max_name_length),
                                    )
                                )

                sql_queries = table_renames + column_renames
                if not sql_queries:
                    print("No changes needed")
                else:
                    with connection.cursor() as cursor:
                        for sql in table_renames + column_renames:
                            print("executing: " + sql)
                            cursor.execute(sql)
                            print("done")

    operations = [migrations.RunPython(check_nemo_6_0_0_oracle_long_names, check_nemo_6_0_0_oracle_long_names_reverse)]


def old_quote_name(name, max_name_length):
    if not name.startswith('"') and not name.endswith('"'):
        name = '"%s"' % truncate_name(name.upper(), max_name_length)
    name = name.replace("%", "%%")
    return name.upper()


def split_identifier(identifier):
    """
    Split an SQL identifier into a two element tuple of (namespace, name).

    The identifier could be a table, column, or sequence name might be prefixed
    by a namespace.
    """
    try:
        namespace, name = identifier.split('"."')
    except ValueError:
        namespace, name = "", identifier
    return namespace.strip('"'), name.strip('"')


def truncate_name(identifier, length=None, hash_len=4):
    """
    Shorten an SQL identifier to a repeatable mangled version with the given
    length.

    If a quote stripped name contains a namespace, e.g. USERNAME"."TABLE,
    truncate the table portion only.
    """
    namespace, name = split_identifier(identifier)

    if length is None or len(name) <= length:
        return identifier

    digest = names_digest(name, length=hash_len)
    return "%s%s%s" % ('%s"."' % namespace if namespace else "", name[: length - hash_len], digest)


def names_digest(*args, length):
    """
    Generate a 32-bit digest of a set of arguments that can be used to shorten
    identifying names.
    """
    h = hashlib.md5()
    for arg in args:
        h.update(arg.encode())
    return h.hexdigest()[:length]


def strip_quotes(table_name):
    """
    Strip quotes off of quoted table names to make them safe for use in index
    names, sequence names, etc. For example '"USER"."TABLE"' (an Oracle naming
    scheme) becomes 'USER"."TABLE'.
    """
    has_quotes = table_name.startswith('"') and table_name.endswith('"')
    return table_name[1:-1] if has_quotes else table_name
