import { MigrationInterface, QueryRunner } from 'typeorm';

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

  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      CREATE TABLE IF NOT EXISTS freight.wagon_types (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        code VARCHAR(32) NOT NULL UNIQUE,
        name VARCHAR(100) NOT NULL,
        capacity_tons NUMERIC(10,3) NOT NULL,
        length_meters NUMERIC(10,3) NOT NULL,
        max_wagons_per_train INT NULL,
        supported_load_types TEXT[] NOT NULL DEFAULT '{}',
        is_active BOOLEAN NOT NULL DEFAULT true,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        deleted_at TIMESTAMPTZ NULL
      );
    `);

    await queryRunner.query(`
      CREATE TABLE IF NOT EXISTS freight.locomotives (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        code VARCHAR(32) NOT NULL UNIQUE,
        name VARCHAR(100) NULL,
        max_pull_weight_tons NUMERIC(10,3) NOT NULL,
        status VARCHAR(20) NOT NULL DEFAULT 'AVAILABLE',
        available_from TIMESTAMPTZ NULL,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        deleted_at TIMESTAMPTZ NULL
      );
    `);

    await queryRunner.query(`
      CREATE TABLE IF NOT EXISTS freight.train_sets (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        locomotive_id UUID NOT NULL,
        total_weight_tons NUMERIC(10,3) NOT NULL,
        total_length_meters NUMERIC(10,3) NOT NULL,
        wagon_count INT NOT NULL,
        status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        deleted_at TIMESTAMPTZ NULL,
        CONSTRAINT fk_train_sets_locomotive FOREIGN KEY (locomotive_id)
          REFERENCES freight.locomotives(id)
      );
    `);

    await queryRunner.query(`
      CREATE TABLE IF NOT EXISTS freight.train_set_wagons (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        train_set_id UUID NOT NULL,
        wagon_type_id UUID NOT NULL,
        sequence_no INT NOT NULL,
        capacity_tons NUMERIC(10,3) NOT NULL,
        length_meters NUMERIC(10,3) NOT NULL,
        assigned_weight_tons NUMERIC(10,3) NOT NULL DEFAULT 0,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        deleted_at TIMESTAMPTZ NULL,
        CONSTRAINT uq_train_set_wagons_sequence UNIQUE (train_set_id, sequence_no),
        CONSTRAINT fk_train_set_wagons_train_set FOREIGN KEY (train_set_id)
          REFERENCES freight.train_sets(id) ON DELETE CASCADE,
        CONSTRAINT fk_train_set_wagons_wagon_type FOREIGN KEY (wagon_type_id)
          REFERENCES freight.wagon_types(id)
      );
    `);

    await queryRunner.query(`
      CREATE TABLE IF NOT EXISTS freight.train_schedules (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        train_set_id UUID NOT NULL UNIQUE,
        origin_station_id UUID NOT NULL,
        destination_station_id UUID NOT NULL,
        scheduled_departure_date TIMESTAMPTZ NOT NULL,
        scheduled_arrival_date TIMESTAMPTZ NULL,
        status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        deleted_at TIMESTAMPTZ NULL,
        CONSTRAINT fk_train_schedules_train_set FOREIGN KEY (train_set_id)
          REFERENCES freight.train_sets(id),
        CONSTRAINT fk_train_schedules_origin FOREIGN KEY (origin_station_id)
          REFERENCES freight.yards(id),
        CONSTRAINT fk_train_schedules_destination FOREIGN KEY (destination_station_id)
          REFERENCES freight.yards(id)
      );
    `);

    await queryRunner.query(`
      CREATE TABLE IF NOT EXISTS freight.train_schedule_bookings (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        train_schedule_id UUID NOT NULL,
        booking_id UUID NOT NULL UNIQUE,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        deleted_at TIMESTAMPTZ NULL,
        CONSTRAINT uq_train_schedule_booking UNIQUE (train_schedule_id, booking_id),
        CONSTRAINT fk_train_schedule_bookings_schedule FOREIGN KEY (train_schedule_id)
          REFERENCES freight.train_schedules(id) ON DELETE CASCADE,
        CONSTRAINT fk_train_schedule_bookings_booking FOREIGN KEY (booking_id)
          REFERENCES freight.bookings(id)
      );
    `);

    await queryRunner.query(`
      CREATE TABLE IF NOT EXISTS freight.wagon_booking_allocations (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        train_set_wagon_id UUID NOT NULL,
        booking_id UUID NOT NULL,
        allocated_weight_tons NUMERIC(10,3) NOT NULL,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        deleted_at TIMESTAMPTZ NULL,
        CONSTRAINT fk_wagon_booking_allocations_wagon FOREIGN KEY (train_set_wagon_id)
          REFERENCES freight.train_set_wagons(id) ON DELETE CASCADE,
        CONSTRAINT fk_wagon_booking_allocations_booking FOREIGN KEY (booking_id)
          REFERENCES freight.bookings(id)
      );
    `);

    await queryRunner.query(`
      CREATE INDEX IF NOT EXISTS idx_locomotives_status
      ON freight.locomotives(status);
    `);
    await queryRunner.query(`
      CREATE INDEX IF NOT EXISTS idx_train_sets_status
      ON freight.train_sets(status);
    `);
    await queryRunner.query(`
      CREATE INDEX IF NOT EXISTS idx_train_schedules_departure_status
      ON freight.train_schedules(scheduled_departure_date, status);
    `);
    await queryRunner.query(`
      CREATE INDEX IF NOT EXISTS idx_wagon_booking_allocations_booking
      ON freight.wagon_booking_allocations(booking_id);
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP TABLE IF EXISTS freight.wagon_booking_allocations;`);
    await queryRunner.query(`DROP TABLE IF EXISTS freight.train_schedule_bookings;`);
    await queryRunner.query(`DROP TABLE IF EXISTS freight.train_schedules;`);
    await queryRunner.query(`DROP TABLE IF EXISTS freight.train_set_wagons;`);
    await queryRunner.query(`DROP TABLE IF EXISTS freight.train_sets;`);
    await queryRunner.query(`DROP TABLE IF EXISTS freight.locomotives;`);
    await queryRunner.query(`DROP TABLE IF EXISTS freight.wagon_types;`);
  }
}
