import { MigrationInterface, QueryRunner } from 'typeorm';

type FleetRow = {
  code: string;
  name: string;
  count: number;
  start: number;
  end: number;
  capacityTons: number;
  tareWeight: number;
  lengthMeters: number;
  supportedLoadTypes: string[];
};

const FLEET: FleetRow[] = [
  {
    code: 'PW2',
    name: 'Box wagon',
    count: 220,
    start: 1,
    end: 220,
    capacityTons: 70,
    tareWeight: 25.2,
    lengthMeters: 17.066,
    supportedLoadTypes: ['BULK', 'GENERAL_CARGO', 'BAGGED_CARGO', 'BOXED_CARGO'],
  },
  {
    code: 'CW4',
    name: 'Gondola wagon covered',
    count: 110,
    start: 221,
    end: 330,
    capacityTons: 70,
    tareWeight: 24.8,
    lengthMeters: 13.976,
    supportedLoadTypes: ['CONTAINER'],
  },
  {
    code: 'CW3',
    name: 'Gondola wagon',
    count: 20,
    start: 331,
    end: 350,
    capacityTons: 70,
    tareWeight: 23.4,
    lengthMeters: 13.976,
    supportedLoadTypes: ['BULK', 'COAL', 'ORE'],
  },
  {
    code: 'KW2',
    name: 'Hopper wagon covered',
    count: 20,
    start: 351,
    end: 370,
    capacityTons: 69,
    tareWeight: 25.2,
    lengthMeters: 16.466,
    supportedLoadTypes: ['BULK', 'GRAIN'],
  },
  {
    code: 'KW3',
    name: 'Hopper wagon',
    count: 20,
    start: 371,
    end: 390,
    capacityTons: 70,
    tareWeight: 24,
    lengthMeters: 14.4,
    supportedLoadTypes: ['BULK', 'COAL'],
  },
  {
    code: 'NW5',
    name: 'Flat wagon container',
    count: 550,
    start: 391,
    end: 940,
    capacityTons: 70,
    tareWeight: 0,
    lengthMeters: 14,
    supportedLoadTypes: ['CONTAINER'],
  },
];

const wagonNumber = (sequence: number) => `ER${String(sequence).padStart(4, '0')}`;

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

  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      UPDATE freight.wagon_types
      SET name = 'Flat wagon container',
          capacity_tons = 70,
          length_meters = 14.000,
          supported_load_types = ARRAY['CONTAINER'],
          max_wagons_per_train = 53,
          is_active = true,
          deleted_at = NULL,
          updated_at = now()
      WHERE code = 'NW5';
    `);

    const [defaultLocation] = await queryRunner.query(`
      SELECT id
      FROM freight.yards
      WHERE code IN ('DJIBOUTI', 'DJIB_PORT', 'NAGAD')
         OR lower(label) LIKE '%djibouti%'
      ORDER BY
        CASE code
          WHEN 'DJIBOUTI' THEN 1
          WHEN 'DJIB_PORT' THEN 2
          WHEN 'NAGAD' THEN 3
          ELSE 4
        END,
        display_order ASC
      LIMIT 1;
    `);
    const defaultLocationYardId = defaultLocation?.id ?? null;

    for (const row of FLEET) {
      await queryRunner.query(
        `
          INSERT INTO freight.wagon_types (
            code,
            name,
            capacity_tons,
            length_meters,
            max_wagons_per_train,
            supported_load_types,
            is_active
          )
          VALUES ($1, $2, $3, $4, $5, $6::text[], true)
          ON CONFLICT (code) DO UPDATE SET
            name = EXCLUDED.name,
            capacity_tons = EXCLUDED.capacity_tons,
            length_meters = EXCLUDED.length_meters,
            max_wagons_per_train = EXCLUDED.max_wagons_per_train,
            supported_load_types = EXCLUDED.supported_load_types,
            is_active = true,
            deleted_at = NULL,
            updated_at = now();
        `,
        [
          row.code,
          row.name,
          row.capacityTons,
          row.lengthMeters,
          row.supportedLoadTypes.includes('CONTAINER') ? 53 : 37,
          row.supportedLoadTypes,
        ],
      );

      const [typeRecord] = await queryRunner.query(
        `SELECT id FROM freight.wagon_types WHERE code = $1 LIMIT 1;`,
        [row.code],
      );

      if (!typeRecord?.id) {
        throw new Error(`wagon_type_seed_failed:${row.code}`);
      }

      if (row.end - row.start + 1 !== row.count) {
        throw new Error(`wagon_range_mismatch:${row.code}`);
      }

      for (let sequence = row.start; sequence <= row.end; sequence += 1) {
        await queryRunner.query(
          `
            INSERT INTO freight.wagons (
              wagon_number,
              wagon_type_id,
              tare_weight,
              max_payload_weight,
              current_location_yard_id,
              status,
              notes
            )
            VALUES ($1, $2, $3, $4, $5, $6, $7)
            ON CONFLICT (wagon_number) DO UPDATE SET
              wagon_type_id = EXCLUDED.wagon_type_id,
              tare_weight = EXCLUDED.tare_weight,
              max_payload_weight = EXCLUDED.max_payload_weight,
              current_location_yard_id = CASE
                WHEN freight.wagons.train_id IS NULL THEN EXCLUDED.current_location_yard_id
                ELSE freight.wagons.current_location_yard_id
              END,
              status = CASE
                WHEN freight.wagons.train_id IS NULL THEN EXCLUDED.status
                ELSE freight.wagons.status
              END,
              notes = EXCLUDED.notes,
              updated_at = now();
          `,
          [
            wagonNumber(sequence),
            typeRecord.id,
            row.tareWeight,
            row.capacityTons,
            defaultLocationYardId,
            defaultLocationYardId ? 'IMPORT_READY' : 'AVAILABLE',
            `Seeded Ethio-Djibouti Railway ${row.code} fleet record.`,
          ],
        );
      }
    }
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      DELETE FROM freight.wagons
      WHERE wagon_number BETWEEN 'ER0001' AND 'ER0940';
    `);
  }
}
