/**
 * BULK IMPORT journey 4 — nobody pays in the first window cycle: both
 * reserved wheat bookings expire, the cycle concludes NOT-full and the window
 * REOPENS for a second cycle on the same bulk train. A fresh 700 T booking
 * arrives in cycle 2, pays, and allocates.
 *
 * Sequential steps of one journey — retries off.
 */

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

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

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

describe("bulk import: dead first cycle — expire all, reopen, book again", { retries: 0 }, () => {
  before(() => {
    cy.task("db:seedFile", "seed-import-corridor.sql");
    ["BRA", "BRB", "BRC"].forEach((suffix) =>
      seedImportContract({ suffix, reference: stampedRef(suffix), freight: "BULK" }),
    );
  });

  it("operations prepares the corridor bulk train — first window opens (cycle 1)", () => {
    ensureCorridorRoute();
    resetCorridorDay(DEPARTURE);
    createImportSchedule({
      departure: DEPARTURE,
      locoPair: ["LOCO-IMP-23", "LOCO-IMP-24"],
      kind: "bulk",
    });
    withSchedule(DEPARTURE, (s) => forceWindowOpen(s.id, 45));
    withSchedule(DEPARTURE, (s) => expect(s.booking_cycle_no, "cycle 1").to.eq(1));
  });

  it("two customers book wheat and are reserved in cycle 1", () => {
    bookBulk({ suffix: "BRA", tons: 1400, scheduledDate: BOOKING_DAY });
    bookBulk({ suffix: "BRB", tons: 1400, scheduledDate: BOOKING_DAY });
    ["BRA", "BRB"].forEach((suffix) => acceptOperation(suffix));
    withSchedule(DEPARTURE, (s) => {
      closeBookingWindow(s.id);
      completeDocReview(s.id);
    });
    ["BRA", "BRB"].forEach((suffix) =>
      pollBookingStatus(suffix, ["SELECTED_FOR_BATCH", "AWAITING_PAYMENT"]),
    );
  });

  it("nobody pays — both reservations expire and the cycle concludes not-full", () => {
    ["BRA", "BRB"].forEach((suffix) => forceReservationExpiry(suffix));
    withSchedule(DEPARTURE, (s) => {
      endPaymentPhase(s.id);
      // When the reopen instant falls inside office hours, the 10s tick's
      // guard-loop chains PRE_WINDOW straight into OPEN within the SAME tick
      // (booking-window.service.ts advanceSchedule), so PRE_WINDOW is not a
      // reliably observable resting state — assert the cycle left PAYMENT
      // without concluding FULL/DONE, whichever phase it lands on.
      pollDb<ScheduleRow>(
        "window concludes not-full (PRE_WINDOW or fast-forwarded to OPEN)",
        `SELECT window_phase FROM freight.train_schedules WHERE id = $1`,
        [s.id],
        (row) => !!row && row.window_phase !== "PAYMENT" && row.window_phase !== "DONE",
      );
    });
  });

  it("the second window opens (cycle 2) and a fresh 700 T booking pays and allocates", () => {
    withSchedule(DEPARTURE, (s) => forceWindowOpen(s.id, 45));
    withSchedule(DEPARTURE, (s) => expect(s.booking_cycle_no, "cycle 2").to.eq(2));

    bookBulk({ suffix: "BRC", tons: 700, scheduledDate: BOOKING_DAY });
    acceptOperation("BRC");
    withSchedule(DEPARTURE, (s) => {
      closeBookingWindow(s.id);
      completeDocReview(s.id);
    });
    pollBookingStatus("BRC", ["SELECTED_FOR_BATCH", "AWAITING_PAYMENT"]);
    markPaid("BRC");
    pollAllocations("BRC", 10);

    ["BRA", "BRB"].forEach((suffix) =>
      withBooking(suffix, (b) => expect(b.status, `${suffix} stays expired`).to.eq("EXPIRED")),
    );
    withSchedule(DEPARTURE, (s) => {
      withBooking("BRC", (b) => {
        expect(b.train_schedule_id, "BRC rides the reopened train").to.eq(s.id);
      });
    });
  });
});

export {};
