/**
 * BULK IMPORT journey 2 — the CW4 train fills from THREE wheat bookings;
 * three more sit in the waiting pool of the same (first) window. The three
 * selected pay and allocate; when the cycle concludes FULL the three waiting
 * bookings expire with the day.
 *
 * Tonnage (70 T per CW4 wagon, 54-wagon consist):
 *   selected: BWA 1 400 T = 20w, BWB 1 400 T = 20w, BWC 980 T = 14w → Σ 54
 *   waiting:  BW1/BW2/BW3 700 T = 10w each
 *
 * Sequential steps of one journey — retries off.
 */

import {
  acceptOperation,
  bookBulk,
  closeBookingWindow,
  completeDocReview,
  createImportSchedule,
  db,
  departureAt,
  eatDayStr,
  endPaymentPhase,
  ensureCorridorRoute,
  forceWindowOpen,
  markPaid,
  pollAllocations,
  pollBookingStatus,
  pollDb,
  resetCorridorDay,
  seedImportContract,
  setPriority,
  withBooking,
  withSchedule,
  type ScheduleRow,
} from "./import-utils";

const DEPARTURE = departureAt(11);
const BOOKING_DAY = eatDayStr(DEPARTURE);

const stamp = String(Date.now());
const stampedRef = (suffix: string) => `CTR-IMP-${stamp}-${suffix}`;

const SELECTED = [
  { suffix: "BWA", tons: 1400, wagons: 20 },
  { suffix: "BWB", tons: 1400, wagons: 20 },
  { suffix: "BWC", tons: 980, wagons: 14 },
];
const WAITING = [
  { suffix: "BW1", tons: 700, wagons: 10 },
  { suffix: "BW2", tons: 700, wagons: 10 },
  { suffix: "BW3", tons: 700, wagons: 10 },
];
const ALL = [...SELECTED, ...WAITING];

describe("bulk import: 3 bookings fill the train, 3 wait and expire", { retries: 0 }, () => {
  before(() => {
    cy.task("db:seedFile", "seed-import-corridor.sql");
    ALL.forEach((b) =>
      seedImportContract({ suffix: b.suffix, reference: stampedRef(b.suffix), freight: "BULK" }),
    );
  });

  it("operations prepares the corridor and a 54-wagon bulk train with an open first window", () => {
    ensureCorridorRoute();
    resetCorridorDay(DEPARTURE);
    createImportSchedule({
      departure: DEPARTURE,
      locoPair: ["LOCO-IMP-17", "LOCO-IMP-18"],
      kind: "bulk",
    });
    withSchedule(DEPARTURE, (s) => forceWindowOpen(s.id, 45));
  });

  it("six customers book wheat in the first window; operations accepts all six", () => {
    ALL.forEach((b) => {
      bookBulk({ suffix: b.suffix, tons: b.tons, scheduledDate: BOOKING_DAY });
      acceptOperation(b.suffix);
    });
    ALL.forEach((b, i) => setPriority(b.suffix, i + 1));
  });

  it("the batch selects exactly the three that fill 54 wagons; the rest keep waiting", () => {
    withSchedule(DEPARTURE, (s) => {
      closeBookingWindow(s.id);
      completeDocReview(s.id);
    });
    SELECTED.forEach((b) =>
      pollBookingStatus(b.suffix, ["SELECTED_FOR_BATCH", "AWAITING_PAYMENT"]),
    );
    WAITING.forEach((b) =>
      withBooking(b.suffix, (row) => {
        expect(row.status, `${b.suffix} still waiting`).to.eq("FULLY_EXECUTED");
        expect(row.payment_deadline, `${b.suffix} has no pay deadline`).to.be.null;
      }),
    );
  });

  it("the three selected bookings pay and allocate — 54/54", () => {
    SELECTED.forEach((b) => {
      markPaid(b.suffix);
      pollAllocations(b.suffix, b.wagons);
    });
    withSchedule(DEPARTURE, (s) => {
      db<{ n: string }>(
        `SELECT count(DISTINCT wba.train_set_wagon_id) AS n
         FROM freight.wagon_booking_allocations wba
         JOIN freight.train_schedule_bookings tsb
           ON tsb.booking_id = wba.booking_id AND tsb.train_schedule_id = $1
         WHERE wba.deleted_at IS NULL AND tsb.deleted_at IS NULL`,
        [s.id],
      ).then(({ rows }) => expect(Number(rows[0].n), "54 wagons allocated").to.eq(54));
    });
  });

  it("the cycle concludes FULL — the three waiting bookings expire with the day", () => {
    withSchedule(DEPARTURE, (s) => {
      endPaymentPhase(s.id);
      pollDb<ScheduleRow>(
        "window FULL + DONE",
        `SELECT window_phase, booking_window_status FROM freight.train_schedules WHERE id = $1`,
        [s.id],
        (row) => row?.booking_window_status === "FULL" && row?.window_phase === "DONE",
      );
    });
    WAITING.forEach((b) => pollBookingStatus(b.suffix, "EXPIRED"));
    SELECTED.forEach((b) =>
      withBooking(b.suffix, (row) => expect(row.status, `${b.suffix} stays PAID`).to.eq("PAID")),
    );
  });
});

export {};
