import { MigrationInterface, QueryRunner } from 'typeorm';

/**
 * Adds train_schedules.reference: a human-facing unique schedule number
 * S-YYYY-NNNNN (per-year sequence, like bookings' BK-YYYY-NNNNNN).
 *
 *  - Adds the nullable column.
 *  - Backfills existing rows: within each created-at year, numbers rows by
 *    created_at ascending (oldest → S-<year>-00001). Deterministic order.
 *  - Adds a partial unique index (NULLs allowed so a future insert can stage
 *    the row before the app stamps its reference).
 */
export class AddTrainScheduleReference2030000000000
  implements MigrationInterface
{
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      ALTER TABLE freight.train_schedules
        ADD COLUMN IF NOT EXISTS reference VARCHAR(20);
    `);

    // Backfill per-year, ordered by created_at (oldest = 00001). Uses the row's
    // own created-at year as the reference year so historical rows keep a
    // sensible number.
    await queryRunner.query(`
      WITH numbered AS (
        SELECT
          id,
          EXTRACT(YEAR FROM created_at)::int AS yr,
          ROW_NUMBER() OVER (
            PARTITION BY EXTRACT(YEAR FROM created_at)
            ORDER BY created_at ASC, id ASC
          ) AS seq
        FROM freight.train_schedules
        WHERE reference IS NULL
      )
      UPDATE freight.train_schedules ts
      SET reference = 'S-' || numbered.yr || '-' || LPAD(numbered.seq::text, 5, '0')
      FROM numbered
      WHERE ts.id = numbered.id;
    `);

    await queryRunner.query(`
      CREATE UNIQUE INDEX IF NOT EXISTS ux_train_schedules_reference
        ON freight.train_schedules (reference)
        WHERE reference IS NOT NULL;
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      DROP INDEX IF EXISTS freight.ux_train_schedules_reference;
    `);
    await queryRunner.query(`
      ALTER TABLE freight.train_schedules DROP COLUMN IF EXISTS reference;
    `);
  }
}
