import { MigrationInterface, QueryRunner } from 'typeorm';

/**
 * Wagons are now soft-deleted (deleted_at) instead of hard-deleted. The plain
 * UNIQUE on wagon_number would keep a retired wagon's number reserved forever
 * and block ever re-registering that number. Swap it for a PARTIAL unique index
 * that only constrains live rows (deleted_at IS NULL); soft-deleted wagons no
 * longer occupy their number.
 *
 * NOTE: the shared dev DB has no applied migration history, so this is also
 * hand-applied there. The DO blocks + IF EXISTS/IF NOT EXISTS keep it
 * idempotent whether the original uniqueness is the auto-named column
 * constraint (wagons_wagon_number_key) or a TypeORM-named UQ_* constraint/index.
 */
export class WagonNumberPartialUnique2280000000000 implements MigrationInterface {
  name = 'WagonNumberPartialUnique2280000000000';

  public async up(queryRunner: QueryRunner): Promise<void> {
    // Drop any UNIQUE constraint on freight.wagons(wagon_number), whatever it is
    // named (dropping the constraint also drops its backing index).
    await queryRunner.query(`
      DO $$
      DECLARE con_name text;
      BEGIN
        FOR con_name IN
          SELECT conname
            FROM pg_constraint
           WHERE conrelid = 'freight.wagons'::regclass
             AND contype = 'u'
             AND pg_get_constraintdef(oid) ILIKE '%(wagon_number)%'
        LOOP
          EXECUTE format('ALTER TABLE freight.wagons DROP CONSTRAINT IF EXISTS %I', con_name);
        END LOOP;
      END $$;
    `);

    // Drop any standalone (non-partial) unique index on wagon_number too.
    await queryRunner.query(`
      DO $$
      DECLARE idx_name text;
      BEGIN
        FOR idx_name IN
          SELECT c.relname
            FROM pg_index i
            JOIN pg_class c ON c.oid = i.indexrelid
           WHERE i.indrelid = 'freight.wagons'::regclass
             AND i.indisunique
             AND i.indpred IS NULL
             AND c.relname <> 'UQ_wagons_wagon_number_active'
             AND pg_get_indexdef(i.indexrelid) ILIKE '%(wagon_number)%'
        LOOP
          EXECUTE format('DROP INDEX IF EXISTS freight.%I', idx_name);
        END LOOP;
      END $$;
    `);

    // Live wagon numbers stay unique; soft-deleted rows are exempt.
    await queryRunner.query(`
      CREATE UNIQUE INDEX IF NOT EXISTS "UQ_wagons_wagon_number_active"
        ON freight.wagons (wagon_number)
        WHERE deleted_at IS NULL;
    `);
  }

  public async down(): Promise<void> {
    // No-op: re-adding a plain UNIQUE would fail whenever two soft-deleted
    // wagons share a number, and the partial index is strictly safer. Left in
    // place intentionally.
  }
}
