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

/**
 * Portal search empty-state — asserts /search's outboundReason drives a message specific to WHY
 * zero results came back, instead of the old one-size-fits-all "No trains available" copy (see
 * SearchService.classifyEmptySearch + results/page.tsx's emptyReasonCopy). Each test isolates its
 * own route/station/schedule (never mutates the shared seed fixtures) so it can run alongside the
 * rest of the portal suite without disturbing other specs' assumptions about the seeded trip.
 */

function auth() {
  return { Authorization: `Bearer ${staffToken()}` };
}

/** Days-from-now at 06:00Z, matching seed-ui's sampleDepartAt() convention (same-day in Addis TZ). */
function daysFromNowDate(days: number): string {
  const d = new Date();
  d.setUTCDate(d.getUTCDate() + days);
  d.setUTCHours(6, 0, 0, 0);
  return d.toISOString().slice(0, 10);
}

/** resultsUrl() hardcodes STATIONS.A→C and sampleDepartDate() — these tests need other pairs/dates. */
function customResultsUrl(originId: string, destinationId: string, date: string, adults = 1) {
  const p = new URLSearchParams({
    origin: originId,
    destination: destinationId,
    date,
    tripType: "ONE_WAY",
    adults: String(adults),
    children: "0",
    nationality: "ETHIOPIAN",
  });
  return `/booking/results?${p.toString()}`;
}

test("empty-state: fully booked shows a fully-booked message, not a generic one", async ({ page }) => {
  // The seeded trip (UI_IDS.schedule) has 48 seats total — asking for far more than that guarantees
  // zero seat classes satisfy the party size, without needing to actually consume real seats.
  await page.goto(resultsUrl({ adults: 500 }), { waitUntil: "domcontentloaded" });

  await expect(page.getByRole("heading", { name: "Fully booked" })).toBeVisible({ timeout: 20_000 });
  await expect(page.getByText(/fully booked on/i)).toBeVisible();
});

test("empty-state: no schedule that day shows the generic no-trains message", async ({ page }) => {
  // ROUTE_ID/STATIONS A→C is a real, active route — just pick a date far enough out that no
  // schedule was ever created for it.
  const farDate = daysFromNowDate(300);
  await page.goto(customResultsUrl(STATIONS.A, STATIONS.C, farDate), { waitUntil: "domcontentloaded" });

  await expect(page.getByRole("heading", { name: "No trains available" })).toBeVisible({ timeout: 20_000 });
  await expect(page.getByText(/no trains available on/i)).toBeVisible();
});

test("empty-state: a cancelled departure says so, not \"no trains available\"", async ({ page, request }) => {
  const routeRes = await request.post(`${API_URL}/routes`, {
    headers: auth(),
    data: {
      code: `E2E-EMPTY-CANCELLED-${Date.now()}`,
      name: "E2E Empty Cancelled Route",
      effectiveFrom: "2020-01-01T00:00:00Z",
      stops: [
        { stationId: STATIONS.A, sequence: 1, distanceKm: 0 },
        { stationId: STATIONS.C, sequence: 2, distanceKm: 100 },
      ],
    },
  });
  expect(routeRes.ok()).toBeTruthy();
  const route = (await routeRes.json())?.data;

  const templateRes = await request.put(`${API_URL}/routes/${route.id}/coaches`, {
    headers: auth(),
    data: { coaches: [{ coachId: UI_IDS.coach, positionNumber: 1 }] },
  });
  expect(templateRes.ok()).toBeTruthy();

  const date = daysFromNowDate(60);
  const dep = new Date(`${date}T06:00:00Z`);
  const arr = new Date(dep.getTime() + 4 * 3600_000);
  const scheduleRes = await request.post(`${API_URL}/schedules`, {
    headers: auth(),
    data: { trainId: UI_IDS.train, routeId: route.id, departureAt: dep.toISOString(), arrivalAt: arr.toISOString() },
  });
  expect(scheduleRes.ok()).toBeTruthy();
  const schedule = (await scheduleRes.json())?.data;

  const cancelRes = await request.patch(`${API_URL}/schedules/${schedule.id}/status`, {
    headers: auth(),
    data: { status: "CANCELLED" },
  });
  expect(cancelRes.ok()).toBeTruthy();

  await page.goto(customResultsUrl(STATIONS.A, STATIONS.C, date), { waitUntil: "domcontentloaded" });

  await expect(page.getByText("Departure cancelled")).toBeVisible({ timeout: 20_000 });
  await expect(page.getByText(/was cancelled/i)).toBeVisible();
});

test("empty-state: an unconnected station pair says EDR doesn't run there, with no date picker", async ({
  page,
  request,
}) => {
  const stationRes = await request.post(`${API_URL}/stations`, {
    headers: auth(),
    data: { code: `E2E-ISO-${Date.now() % 100000}`, name: "E2E Isolated Station", city: "Nowhere" },
  });
  expect(stationRes.ok()).toBeTruthy();
  const isolatedStation = (await stationRes.json())?.data;

  await page.goto(customResultsUrl(STATIONS.A, isolatedStation.id, sampleDepartDate()), {
    waitUntil: "domcontentloaded",
  });

  await expect(page.getByText("Route not available")).toBeVisible({ timeout: 20_000 });
  await expect(page.getByText(/doesn't currently run trains between/i)).toBeVisible();
  // NO_ROUTE is not fixable by picking another date — no calendar/"Change Date" affordance.
  await expect(page.getByText(/change date/i)).toHaveCount(0);
  await expect(page.getByRole("button", { name: /modify search/i })).toBeVisible();
});
