"""Defines the ``DatabaseSchemaEditor`` class of the ``mtp_db_backend``"""

from django.db.backends.postgresql_psycopg2.schema import (
    DatabaseSchemaEditor as BaseDatabaseSchemaEditor
)


class SqlUniqueDeferrableForSortOrder(str):
    """String with interpolation interception to manage "sort_order" constraints.

    The goal is, for this field, to have the following SQL:

        ``UNIQUE (%(columns)s) DEFERRABLE INITIALLY DEFERRED``

    instead of simply

        ``UNIQUE (%(columns)s)``

    """

    deferrable_sql = '%(default_sql)s DEFERRABLE INITIALLY DEFERRED'

    def __mod__(self, data):
        """Override string interpolation to intercept `sort_order` and update the constraint.

        First the default interpolation is done to get the normal "unique" sql constraint.
        Then we check if the ``columns`` entry of the ``data`` dict contains one named "sort_order"
        and if True, we use ``deferrable_sql`` to compose the final sql.

        """

        # Get the default sql
        result = super().__mod__(data)

        # We need to read the colums to check for "sort_order"
        # Columns is a string with column name separated by comma, all part being encapsulated in "
        # Example: '"sort_order", "training_id"'
        columns = data['columns'][1:-1].split('", "')

        # If "sort_order" is in the columns, we add the "DEFERRABLE INITIALLY DEFERRED" part
        if 'sort_order' in columns:
            result = self.deferrable_sql % {
                'default_sql': result
            }

        # And we return the final sql
        return result


class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
    """Override of the default shema editor to manage unique constraints for the "sort_order" field.

    For this we use ``SqlUniqueDeferrableForSortOrder`` that will intercept the interpolation and
    if "sort_order" is in the given columm, will add the "DEFERRABLE INITIALLY DEFERRED" arguments
    to the constraint.

    It's applied to two sql strings:
    - ``sql_create_table_unique``: used when creating a table from scratch, without migration
    - ``sql_create_unique``: used when adding a constraint to an existing table

    """

    sql_create_table_unique = SqlUniqueDeferrableForSortOrder(
        BaseDatabaseSchemaEditor.sql_create_table_unique
    )

    sql_create_unique = SqlUniqueDeferrableForSortOrder(
        BaseDatabaseSchemaEditor.sql_create_unique
    )
