import { test, expect } from "./fixtures/console-gate";
import type { Page } from "@playwright/test";

// TIRREDESIGN-12 — when both schedule cities are filled, the date-picker
// must grey out the days the route does NOT operate. The schedule
// `/days` bitmask is anchored to the requested calendar minimum date:
// bit 0 maps to that exact date, not "base date minus one".

function ymd(date: Date): string {
  return [
    date.getFullYear(),
    String(date.getMonth() + 1).padStart(2, "0"),
    String(date.getDate()).padStart(2, "0"),
  ].join("");
}

function isoYmd(date: Date): string {
  return [
    date.getFullYear(),
    String(date.getMonth() + 1).padStart(2, "0"),
    String(date.getDate()).padStart(2, "0"),
  ].join("-");
}

function addDays(date: Date, days: number): Date {
  const next = new Date(date);
  next.setDate(next.getDate() + days);
  return next;
}

async function visibleCalendarCellClasses(page: Page) {
  return page
    .locator(".p-datepicker td:not(.p-datepicker-other-month) span")
    .evaluateAll((nodes) =>
      nodes.map((node) => ({
        text: node.textContent?.trim(),
        className: node.className,
      })),
    );
}

test("Schedule calendar greys out non-operating days for the route", async ({ page }) => {
  const minDate = addDays(new Date(), -1);
  minDate.setHours(0, 0, 0, 0);
  const dateTo = addDays(minDate, 6);
  const daysRequests: string[] = [];

  await page.route("**/api/flights/v1/*/days/**/schedule/", async (route) => {
    daysRequests.push(route.request().url());
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({ days: `0${"1".repeat(381)}` }),
    });
  });

  await page.goto(
    `/ru-ru/schedule/route/LED-KUF-${ymd(minDate)}-${ymd(dateTo)}-C0`,
  );

  // Open the picker.
  await page.locator("button.p-datepicker-trigger").first().click();
  const panel = page.locator(".p-datepicker-panel, .p-datepicker").first();
  await expect(panel).toBeVisible();

  const minDateDay = String(minDate.getDate());
  const nextDateDay = String(addDays(minDate, 1).getDate());

  await expect.poll(async () => {
    const cells = await visibleCalendarCellClasses(page);
    return cells.find((cell) => cell.text === minDateDay)?.className ?? "";
  }, { timeout: 10000 }).toContain("p-disabled");

  expect(daysRequests[0]).toContain(
    `/days/${isoYmd(minDate)}/382/route/LED-KUF/schedule/`,
  );

  const cells = await visibleCalendarCellClasses(page);
  expect(
    cells.find((cell) => cell.text === nextDateDay)?.className ?? "",
  ).not.toContain("p-disabled");
});

test("Schedule calendar updates an already-open picker when operating days load", async ({ page }) => {
  const minDate = addDays(new Date(), -1);
  minDate.setHours(0, 0, 0, 0);
  const dateTo = addDays(minDate, 6);

  let releaseDays: (() => void) | undefined;
  await page.route("**/api/flights/v1/*/days/**/schedule/", async (route) => {
    await new Promise<void>((resolve) => {
      releaseDays = resolve;
    });
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({ days: `0${"1".repeat(381)}` }),
    });
  });

  await page.goto(
    `/ru-ru/schedule/route/LED-KUF-${ymd(minDate)}-${ymd(dateTo)}-C0`,
  );

  await page.locator("button.p-datepicker-trigger").first().click();
  const panel = page.locator(".p-datepicker-panel, .p-datepicker").first();
  await expect(panel).toBeVisible();

  const visibleDaySelector =
    ".p-datepicker td:not(.p-datepicker-other-month) span";
  const minDateDay = String(minDate.getDate());

  const classBeforeLoad = await page
    .locator(visibleDaySelector)
    .evaluateAll(
      (nodes, day) =>
        nodes
          .map((node) => ({
            text: node.textContent?.trim(),
            className: node.className,
          }))
          .find((cell) => cell.text === day)?.className ?? "",
      minDateDay,
    );
  expect(classBeforeLoad).not.toContain("p-disabled");

  releaseDays?.();

  await expect.poll(async () => {
    const cells = await visibleCalendarCellClasses(page);
    return cells.find((cell) => cell.text === minDateDay)?.className ?? "";
  }, { timeout: 10000 }).toContain("p-disabled");
});

test("Schedule calendar uses the connections days endpoint when transfers are allowed", async ({ page }) => {
  const minDate = addDays(new Date(), -1);
  minDate.setHours(0, 0, 0, 0);
  const dateTo = addDays(minDate, 6);
  const daysRequests: string[] = [];

  await page.route("**/api/flights/v1/*/days/**/schedule/", async (route) => {
    daysRequests.push(route.request().url());
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({ days: `0${"1".repeat(381)}` }),
    });
  });

  await page.goto(
    `/ru-ru/schedule/route/LED-KUF-${ymd(minDate)}-${ymd(dateTo)}`,
  );

  await page.locator("button.p-datepicker-trigger").first().click();
  await expect(
    page.locator(".p-datepicker-panel, .p-datepicker").first(),
  ).toBeVisible();

  await expect
    .poll(() => daysRequests[0] ?? "", { timeout: 10000 })
    .toContain("/connections/LED-KUF-1/schedule/");
  await expect.poll(async () => {
    const cells = await visibleCalendarCellClasses(page);
    return (
      cells.find((cell) => cell.text === String(minDate.getDate()))?.className ??
      ""
    );
  }, { timeout: 10000 }).toContain("p-disabled");
});

test("Schedule return calendar uses swapped route operating days", async ({ page }) => {
  const minDate = addDays(new Date(), -1);
  minDate.setHours(0, 0, 0, 0);
  const dateTo = addDays(minDate, 6);
  const returnFrom = addDays(dateTo, 1);
  const returnTo = addDays(returnFrom, 6);
  const daysRequests: string[] = [];
  const returnMask = `${"1".repeat(7)}0${"1".repeat(374)}`;

  await page.route("**/api/flights/v1/*/days/**/schedule/", async (route) => {
    const url = route.request().url();
    daysRequests.push(url);
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        days: url.includes("/connections/KUF-LED-1/")
          ? returnMask
          : "1".repeat(382),
      }),
    });
  });

  await page.goto(
    `/ru-ru/schedule/route/LED-KUF-${ymd(minDate)}-${ymd(dateTo)}/KUF-LED-${ymd(returnFrom)}-${ymd(returnTo)}`,
  );

  const triggers = page.locator("button.p-datepicker-trigger");
  await expect(triggers).toHaveCount(2);
  await triggers.nth(1).click();
  await expect(
    page.locator(".p-datepicker-panel, .p-datepicker").first(),
  ).toBeVisible();

  await expect
    .poll(
      () => daysRequests.some((url) => url.includes("/connections/KUF-LED-1/")),
      { timeout: 10000 },
    )
    .toBe(true);

  await expect.poll(async () => {
    const cells = await visibleCalendarCellClasses(page);
    return (
      cells.find((cell) => cell.text === String(returnFrom.getDate()))
        ?.className ?? ""
    );
  }, { timeout: 10000 }).toContain("p-disabled");
});
