import { MigrationInterface, QueryRunner } from 'typeorm';

export class Utf8mb4UnicodeCollation1785070800000 implements MigrationInterface {
  name = 'Utf8mb4UnicodeCollation1785070800000';

  public async up(queryRunner: QueryRunner): Promise<void> {
    const database = queryRunner.connection.options.database;

    if (typeof database !== 'string' || database.length === 0) {
      throw new Error('A database name is required to update its collation');
    }

    const escapedDatabase = `\`${database.replace(/`/g, '``')}\``;

    // New tables created by TypeORM inherit this database default.
    await queryRunner.query(
      `ALTER DATABASE ${escapedDatabase} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`,
    );

    const tables = (await queryRunner.query(
      `SELECT TABLE_NAME
       FROM information_schema.TABLES
       WHERE TABLE_SCHEMA = ?
         AND TABLE_TYPE = 'BASE TABLE'`,
      [database],
    )) as Array<{ TABLE_NAME: string }>;

    // CONVERT updates both the table default and all existing character columns.
    // Foreign-key checks must be disabled while related varchar columns are
    // converted one table at a time.
    await queryRunner.query('SET FOREIGN_KEY_CHECKS = 0');
    try {
      for (const { TABLE_NAME: tableName } of tables) {
        const escapedTable = `\`${tableName.replace(/`/g, '``')}\``;
        await queryRunner.query(
          `ALTER TABLE ${escapedDatabase}.${escapedTable} CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`,
        );
      }
    } finally {
      await queryRunner.query('SET FOREIGN_KEY_CHECKS = 1');
    }
  }

  public async down(): Promise<void> {
    // The previous database/table collations can differ per installation, so
    // reverting safely requires a backup of those values and is intentionally
    // not automated.
  }
}
