"""Peewee migrations -- 127_MAIN.py.

This is a partially handwritten migration because of the non-triviality
of migrating sqlite tables to strict ones. Also, peewee being such
a weird orm doesn't help as well.
"""
from contextlib import suppress
from sqlite3 import Cursor

import peewee as pw
from peewee_migrate import Migrator

with suppress(ImportError):
    import playhouse.postgres_ext as pw_pext


TABLES = [
    "batch",
    "batchmaterial",
    "car",
    "companysurcharge",
    "constructionsite",
    "contract",
    "customer",
    "defaults",
    "delivery",
    "driver",
    "lockedtable",
    "material",
    "order",
    "ordermaterial",
    "ordersurcharge",
    "price",
    "pump",
    "pumporder",
    "pumpordersurcharge",
    "pumpsurcharge",
    "recipe",
    "recipematerial",
    "recipeproduction",
    "sample",
    "setup",
    "stockmovement",
    "transporttype",
    "transportzone",
    "user",
]


def run_sql(database: pw.Database, sql: str) -> Cursor:
    return database.execute(pw.SQL(sql))


def create_tmp_model(database: pw.Database, name: str, tmp_name: str, strict: bool) -> None:
    [create_sql] = run_sql(database, f"SELECT sql FROM sqlite_master WHERE type='table' AND tbl_name='{name}';").fetchone()

    create_sql = create_sql.replace(f'"{name}"', f'"{tmp_name}"')
    if strict:
        create_sql += " STRICT"
    else:
        create_sql = create_sql.replace("STRICT", "")

    run_sql(database, create_sql)


def drop_tmp_model_and_recreate_indexes(database: pw.Database, name: str, tmp_name: str) -> None:
    indexes_sql = run_sql(database, f"SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name='{name}';").fetchall()

    run_sql(database, f"DROP TABLE `{name}`;")
    run_sql(database, f"ALTER TABLE `{tmp_name}` RENAME TO `{name}`;")

    for index_sql in indexes_sql:
        run_sql(database, index_sql[0])


def switch_tables(database: pw.Database, *, strict: bool) -> None:
    for name in TABLES:
        tmp_name = name + "2"

        create_tmp_model(database, name, tmp_name, strict)

        run_sql(database, f"INSERT INTO `{tmp_name}` SELECT * FROM `{name}`;")

        drop_tmp_model_and_recreate_indexes(database, name, tmp_name)


def migrate(migrator: Migrator, database: pw.Database, *, fake: bool = False) -> None:
    # First, fix fuck-ups we discovered when migrating to strict mode
    # (someone forgot to generate migrations in the past?)
    migrator.change_fields('batchmaterial', humidity_e1=pw.DoubleField(null=True))
    migrator.change_fields('batchmaterial', humidity_rq=pw.DoubleField(null=True))
    migrator.change_fields('batchmaterial', internal_humidity_rq=pw.DoubleField(null=True))
    migrator.change_fields('constructionsite', distance=pw.DoubleField(null=True))

    migrator.run(switch_tables, database, strict=True)


def rollback(migrator: Migrator, database: pw.Database, *, fake: bool = False) -> None:
    """Write your rollback migrations here."""

    migrator.run(switch_tables, database, strict=False)
