import { orderConsistWagons } from './consist-order.util';

// Built train: A-B-C-D coupled in that order. Slots are created by the wagon
// PLAN, so their sequenceNo says nothing about where the wagon actually sits.
const TRAIN = ['A', 'B', 'C', 'D'];

const slot = (sequenceNo: number, physicalWagonId: string | null) => ({
  sequenceNo,
  physicalWagonId,
});

describe('orderConsistWagons', () => {
  it('draws slots in the train coupling order, not slot order', () => {
    // Plan order says D then B; the train says B sits ahead of D.
    const drawn = orderConsistWagons([slot(1, 'D'), slot(2, 'B')], {
      physicalWagonIdsInOrder: TRAIN,
    });

    expect(drawn.map((w) => w.physicalWagonId)).toEqual(['B', 'D']);
    expect(drawn.map((w) => w.position)).toEqual([1, 2]);
  });

  it('interleaves empty consist wagons in their real place', () => {
    // Loaded slots on A and C; B and D ride along empty. The empties used to be
    // appended after every loaded slot, so the drawing was never the train.
    const drawn = orderConsistWagons(
      [slot(1, 'A'), slot(2, 'C'), slot(98, 'B'), slot(99, 'D')],
      { physicalWagonIdsInOrder: TRAIN },
    );

    expect(drawn.map((w) => w.physicalWagonId)).toEqual(['A', 'B', 'C', 'D']);
  });

  it('keeps every wagon in place when a load moves between wagons', () => {
    // Load sat on A (slot 1); staff drag it onto empty D. The move repins the
    // slot, so the SAME slot now reads as wagon D and A falls back to empty.
    const before = orderConsistWagons([slot(1, 'A'), slot(98, 'D')], {
      physicalWagonIdsInOrder: TRAIN,
    });
    const after = orderConsistWagons([slot(1, 'D'), slot(98, 'A')], {
      physicalWagonIdsInOrder: TRAIN,
    });

    // A is drawn first and D last, before and after — the train did not shuffle.
    expect(before.map((w) => w.physicalWagonId)).toEqual(['A', 'D']);
    expect(after.map((w) => w.physicalWagonId)).toEqual(['A', 'D']);
  });

  it('follows a train-builder reorder without touching any slot row', () => {
    const slots = [slot(1, 'A'), slot(2, 'B')];

    // Builder swaps the coupling order; the slots are untouched.
    const drawn = orderConsistWagons(slots, {
      physicalWagonIdsInOrder: ['B', 'A', 'C', 'D'],
    });

    expect(drawn.map((w) => w.physicalWagonId)).toEqual(['B', 'A']);
  });

  it('draws back-to-front when the caller reverses the train', () => {
    const drawn = orderConsistWagons([slot(1, 'A'), slot(2, 'C')], {
      physicalWagonIdsInOrder: [...TRAIN].reverse(),
      reverseWagonOrder: true,
    });

    expect(drawn.map((w) => w.physicalWagonId)).toEqual(['C', 'A']);
  });

  it('parks unpinned slots last, in slot order', () => {
    const drawn = orderConsistWagons([slot(9, null), slot(4, null), slot(1, 'C')], {
      physicalWagonIdsInOrder: TRAIN,
    });

    expect(drawn.map((w) => [w.physicalWagonId, w.sequenceNo])).toEqual([
      ['C', 1],
      [null, 4],
      [null, 9],
    ]);
  });

  it('falls back to slot order when there is no built train', () => {
    // Frozen schedules and loose-wagon schedules pass no physical order.
    const drawn = orderConsistWagons([slot(2, 'X'), slot(1, 'Y')], {
      physicalWagonIdsInOrder: [],
    });
    expect(drawn.map((w) => w.sequenceNo)).toEqual([1, 2]);

    const reversed = orderConsistWagons([slot(1, 'X'), slot(2, 'Y')], {
      physicalWagonIdsInOrder: [],
      reverseWagonOrder: true,
    });
    expect(reversed.map((w) => w.sequenceNo)).toEqual([2, 1]);
  });
});
