import { test, expect } from "@playwright/test";
import { API_URL, STATIONS, staffToken } from "../../fixtures/data";
import { UI_IDS } from "../../../apps/edr-passenger-api/test/fixtures/seed-ui";

/**
 * Track B — per-station check-in cutoff, driven by the backoffice route config API. Follows the
 * same convention as config-validation.spec.ts: hits the passenger-api directly with a staff
 * bearer token rather than driving the real DOM — the route-stop form has no data-testid hooks,
 * so browser automation here would be selector-fragile for no extra coverage value.
 *
 * Creates its OWN route (not the shared ROUTE_ID from seed-ui) since updateRoute deletes and
 * recreates all stops — mutating the shared fixture route would break every other spec that
 * depends on its distances/times staying stable for the whole suite run.
 */
function auth() {
  return { Authorization: `Bearer ${staffToken()}` };
}

test("BC-11 ✅ travelMinutesToStop drives each stop's estimated arrival independently of route-wide departure", async ({ request }) => {
  const routeRes = await request.post(`${API_URL}/routes`, {
    headers: auth(),
    data: {
      code: `E2E-CUTOFF-${Date.now()}`,
      name: "E2E Check-in Cutoff Route",
      effectiveFrom: "2020-01-01T00:00:00Z",
      stops: [
        { stationId: STATIONS.A, sequence: 1, distanceKm: 0 },
        { stationId: STATIONS.B, sequence: 2, travelMinutesToStop: 60, distanceKm: 60 },
        { stationId: STATIONS.C, sequence: 3, travelMinutesToStop: 40, distanceKm: 100 },
      ],
    },
  });
  expect(routeRes.ok()).toBeTruthy();
  const route = (await routeRes.json())?.data ?? (await routeRes.json());
  const routeId = route.id;

  // Reuse the seeded coach via a route coach template so schedule creation auto-assigns real
  // seats (createSchedule auto-applies any route coach template — see schedules.service.ts).
  const templateRes = await request.put(`${API_URL}/routes/${routeId}/coaches`, {
    headers: auth(),
    data: { coaches: [{ coachId: UI_IDS.coach, positionNumber: 1 }] },
  });
  expect(templateRes.ok()).toBeTruthy();

  // dep only 5 min out: A's cutoff (dep - 30min default) is already ~25 min in the past by the
  // time this schedule is queried, but B's arrival (dep + 60min) keeps its own cutoff (arrival -
  // 30min default) about 35 min in the future — proving the two stations close independently.
  const dep = new Date(Date.now() + 5 * 60_000);
  const arr = new Date(dep.getTime() + 100 * 60_000); // A->B 60min + B->C 40min
  const scheduleRes = await request.post(`${API_URL}/schedules`, {
    headers: auth(),
    data: { trainId: UI_IDS.train, routeId, departureAt: dep.toISOString(), arrivalAt: arr.toISOString() },
  });
  expect(scheduleRes.ok()).toBeTruthy();
  const schedule = (await scheduleRes.json())?.data ?? (await scheduleRes.json());

  const getRes = await request.get(`${API_URL}/schedules/${schedule.id}`, { headers: auth() });
  expect(getRes.ok()).toBeTruthy();
  const full = (await getRes.json())?.data ?? (await getRes.json());
  const stopTimes: any[] = full.stopTimes ?? [];
  const bStop = stopTimes.find((s) => s.stationId === STATIONS.B);
  const cStop = stopTimes.find((s) => s.stationId === STATIONS.C);

  expect(new Date(bStop.plannedArrivalAt).getTime()).toBe(dep.getTime() + 60 * 60_000);
  expect(new Date(cStop.plannedArrivalAt).getTime()).toBe(arr.getTime()); // last stop locked to overall arrival

  // A's own segment (no arrival — falls back to its departure) is already past its cutoff...
  const rejectRes = await request.post(`${API_URL}/seats/hold`, {
    headers: auth(),
    data: {
      scheduleId: schedule.id,
      originStationId: STATIONS.A,
      destinationStationId: STATIONS.B,
      passengers: [{ passengerId: "44444444-4444-4444-8444-444444444444", seatId: "00000000-0000-4000-8000-000000009999" }],
    },
  });
  expect(rejectRes.status()).toBe(400);
  expect((await rejectRes.json())?.message ?? "").toMatch(/cannot be held within/i);

  // ...while B, whose own arrival is comfortably later, remains independently bookable.
  const seatmapRes = await request.get(`${API_URL}/seats/seatmap/${schedule.id}`, { headers: auth() });
  expect(seatmapRes.ok()).toBeTruthy();
  const seatmap = (await seatmapRes.json())?.data ?? (await seatmapRes.json());
  const seatId = seatmap.coaches?.[0]?.seats?.[0]?.id;
  expect(seatId).toBeTruthy();

  const holdRes = await request.post(`${API_URL}/seats/hold`, {
    headers: auth(),
    data: {
      scheduleId: schedule.id,
      originStationId: STATIONS.B,
      destinationStationId: STATIONS.C,
      passengers: [{ passengerId: "55555555-5555-4555-8555-555555555555", seatId }],
    },
  });
  expect(holdRes.ok()).toBeTruthy();

  await request.delete(`${API_URL}/schedules/${schedule.id}`, { headers: auth() }).catch(() => {});
  await request.delete(`${API_URL}/routes/${routeId}?cascade=true`, { headers: auth() }).catch(() => {});
});
