/**
 * GENERAL drawdown ledger (D+25) — one GENERAL contract capped at 60×20ft
 * draws down across many bookings; the cap is enforced at CREATE, releases
 * when a booking dies, and the contract stays CONTRACT_ACTIVE throughout:
 *
 *   B1 30 → B2 20 → B3 asking 20 REJECTED ("only 10 remain") → B3' 10 → cap
 *   exhausted → B4 2 REJECTED → B3' expires → its 10 return → B5 10 accepted.
 *
 * Sequential steps of one journey — retries off.
 */

import {
  bookContainers,
  createImportSchedule,
  db,
  departureAt,
  eatDayStr,
  ensureCorridorRoute,
  forceWindowOpen,
  pollBookingStatus,
  resetCorridorDay,
  seedImportContract,
  withSchedule,
} from "./import-utils";

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

const stamp = String(Date.now());
const SUFFIX = "GDCAP";
const REF = `CTR-IMP-${stamp}-${SUFFIX}`;

describe("GENERAL drawdown: a 60×20ft cap across many bookings", { retries: 0 }, () => {
  before(() => {
    cy.task("db:seedFile", "seed-import-corridor.sql");
    seedImportContract({ suffix: SUFFIX, reference: REF, kind: "GENERAL", cap20: 60 });
  });

  it("operations prepares the corridor train with an open window (bookings need an open day)", () => {
    ensureCorridorRoute();
    resetCorridorDay(DEPARTURE);
    createImportSchedule({ departure: DEPARTURE, locoPair: ["LOCO-IMP-17", "LOCO-IMP-18"] });
    withSchedule(DEPARTURE, (s) => forceWindowOpen(s.id, 60));
  });

  it("B1 draws 30 and B2 draws 20 — 50 of 60 held", () => {
    bookContainers({
      suffix: SUFFIX,
      runStamp: stamp,
      isoSeed: 18_000,
      twenty: 30,
      scheduledDate: BOOKING_DAY,
    });
    bookContainers({
      suffix: SUFFIX,
      runStamp: stamp,
      isoSeed: 18_100,
      twenty: 20,
      scheduledDate: BOOKING_DAY,
    });
    db<{ n: string }>(
      `SELECT count(*) AS n FROM freight.bookings b
       JOIN freight.contracts ct ON ct.id = b.contract_id
       WHERE ct.reference = $1`,
      [REF],
    ).then(({ rows }) => expect(Number(rows[0].n), "two live drawdowns").to.eq(2));
  });

  it("B3 asking 20 is REJECTED — only 10 of 60 remain", () => {
    bookContainers({
      suffix: SUFFIX,
      runStamp: stamp,
      isoSeed: 18_200,
      twenty: 20,
      scheduledDate: BOOKING_DAY,
      expectFailure: "remain on this contract",
    });
  });

  it("B3' takes exactly the remaining 10 — the contract COMPLETES and B4 is rejected", () => {
    bookContainers({
      suffix: SUFFIX,
      runStamp: stamp,
      isoSeed: 18_300,
      twenty: 10,
      scheduledDate: BOOKING_DAY,
    });
    // Booking the last of the cap flips the GENERAL contract to
    // CONTRACT_CLOSED (fully drawn) — the next booking is rejected as such.
    db<{ status: string }>(
      `SELECT status FROM freight.contracts WHERE reference = $1`,
      [REF],
    ).then(({ rows }) =>
      expect(rows[0].status, "fully drawn contract completes").to.eq("CONTRACT_CLOSED"),
    );
    bookContainers({
      suffix: SUFFIX,
      runStamp: stamp,
      isoSeed: 18_400,
      twenty: 2,
      scheduledDate: BOOKING_DAY,
      expectFailure: "completed",
    });
  });

  it("an EXPIRED booking releases its draw — B5 books the freed 10 and the ledger closes again", () => {
    // Kill the newest live drawdown (B3', 10×20ft) — expiry releases its hold.
    db(
      `UPDATE freight.bookings b SET status = 'EXPIRED'
       FROM freight.contracts ct
       WHERE ct.id = b.contract_id AND ct.reference = $1
         AND b.id = (
           SELECT b2.id FROM freight.bookings b2
           JOIN freight.contracts c2 ON c2.id = b2.contract_id
           WHERE c2.reference = $1 AND b2.status NOT IN ('EXPIRED','CANCELLED','REJECTED')
           ORDER BY b2.created_at DESC LIMIT 1
         )`,
      [REF],
    );
    bookContainers({
      suffix: SUFFIX,
      runStamp: stamp,
      isoSeed: 18_500,
      twenty: 10,
      scheduledDate: BOOKING_DAY,
    });
    pollBookingStatus(SUFFIX, "AWAITING_DOCUMENTS", 5);

    // Completion tracks the outstanding quantity: the released 10 were
    // rebooked, so the ledger is full again and the contract stays CLOSED.
    db<{ status: string }>(
      `SELECT status FROM freight.contracts WHERE reference = $1`,
      [REF],
    ).then(({ rows }) =>
      expect(rows[0].status, "re-drawn contract closed").to.eq("CONTRACT_CLOSED"),
    );
  });
});

export {};
