import { MigrationInterface, QueryRunner } from 'typeorm';

/**
 * Train Builder: a `Train` becomes a first-class buildable consist — a coded
 * train (e.g. 81001) assembled in one yard from 2+ locomotives and ordered
 * wagons, then reused by scheduling ("schedule the train" instead of picking
 * locomotives per departure).
 *
 * - `freight.train_locomotives` — link table train ⇄ locomotive with an order
 *   index (mirrors `train_set_locomotives`).
 * - `trains.current_yard_id` — yard the train sits in; wagons/locomotives may
 *   only be attached from this yard.
 * - `train_sets.train_id` — which built train an operational set was formed
 *   from, so schedules can surface the train code and the lifecycle can sync
 *   the train's status/yard on dispatch/arrival/cancel.
 *
 * NOTE: the shared dev DB has no applied migration history, so this is also
 * hand-applied there. IF NOT EXISTS keeps that idempotent.
 */
export class TrainBuilder2150000000000 implements MigrationInterface {
  name = 'TrainBuilder2150000000000';

  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      CREATE TABLE IF NOT EXISTS freight.train_locomotives (
        id uuid NOT NULL DEFAULT uuid_generate_v4(),
        train_id uuid NOT NULL,
        locomotive_id uuid NOT NULL,
        sequence_no int NOT NULL DEFAULT 0,
        created_at timestamptz NOT NULL DEFAULT now(),
        updated_at timestamptz NOT NULL DEFAULT now(),
        deleted_at timestamptz,
        CONSTRAINT "PK_train_locomotives" PRIMARY KEY (id),
        CONSTRAINT "FK_train_locomotives_train" FOREIGN KEY (train_id)
          REFERENCES freight.trains (id) ON DELETE CASCADE,
        CONSTRAINT "FK_train_locomotives_locomotive" FOREIGN KEY (locomotive_id)
          REFERENCES freight.locomotives (id)
      );
    `);

    await queryRunner.query(`
      CREATE UNIQUE INDEX IF NOT EXISTS "UQ_train_locomotives_train_loco"
        ON freight.train_locomotives (train_id, locomotive_id);
    `);

    await queryRunner.query(`
      ALTER TABLE freight.trains
        ADD COLUMN IF NOT EXISTS current_yard_id uuid;
    `);
    await queryRunner.query(`
      DO $$
      BEGIN
        IF NOT EXISTS (
          SELECT 1 FROM pg_constraint WHERE conname = 'FK_trains_current_yard'
        ) THEN
          ALTER TABLE freight.trains
            ADD CONSTRAINT "FK_trains_current_yard" FOREIGN KEY (current_yard_id)
              REFERENCES freight.yards (id) ON DELETE SET NULL;
        END IF;
      END $$;
    `);
    await queryRunner.query(`
      CREATE INDEX IF NOT EXISTS "IDX_trains_current_yard_id"
        ON freight.trains (current_yard_id);
    `);

    await queryRunner.query(`
      ALTER TABLE freight.train_sets
        ADD COLUMN IF NOT EXISTS train_id uuid;
    `);
    await queryRunner.query(`
      DO $$
      BEGIN
        IF NOT EXISTS (
          SELECT 1 FROM pg_constraint WHERE conname = 'FK_train_sets_train'
        ) THEN
          ALTER TABLE freight.train_sets
            ADD CONSTRAINT "FK_train_sets_train" FOREIGN KEY (train_id)
              REFERENCES freight.trains (id) ON DELETE SET NULL;
        END IF;
      END $$;
    `);
    await queryRunner.query(`
      CREATE INDEX IF NOT EXISTS "IDX_train_sets_train_id"
        ON freight.train_sets (train_id);
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_train_sets_train_id";`);
    await queryRunner.query(`
      ALTER TABLE freight.train_sets
        DROP CONSTRAINT IF EXISTS "FK_train_sets_train",
        DROP COLUMN IF EXISTS train_id;
    `);
    await queryRunner.query(`DROP INDEX IF EXISTS freight."IDX_trains_current_yard_id";`);
    await queryRunner.query(`
      ALTER TABLE freight.trains
        DROP CONSTRAINT IF EXISTS "FK_trains_current_yard",
        DROP COLUMN IF EXISTS current_yard_id;
    `);
    await queryRunner.query(`DROP INDEX IF EXISTS freight."UQ_train_locomotives_train_loco";`);
    await queryRunner.query(`DROP TABLE IF EXISTS freight.train_locomotives;`);
  }
}
