// @ts-nocheck
import { test, expect } from "playwright/test";

test("catalog maker shell loads without page errors", async ({ page }) => {
  const pageErrors = [];
  page.on("pageerror", (error) => pageErrors.push(error.message));

  await page.goto("/");
  await expect(page.locator("#settingsButton")).toBeVisible();
  await expect(page.locator("#recordId")).toBeVisible();
  await expect(page.locator("#variantHeader")).toBeVisible();

  await page.screenshot({ path: "test-results/catalog-maker-shell.png", fullPage: true });
  expect(pageErrors).toEqual([]);
});

test("settings modal opens and shows local database controls", async ({ page }) => {
  await page.goto("/");
  await page.locator("#settingsButton").click();

  await expect(page.locator("#settingsModal")).toBeVisible();
  await expect(page.locator("#localDbHost")).toBeVisible();
  await expect(page.locator("#testLocalDbButton")).toBeVisible();
});

test("manufacturer picker shows ten results and supports search", async ({ page }) => {
  await page.goto("/");
  await page.locator("#manufacturerTrigger").click();

  await expect(page.locator("#manufacturerOptions .manufacturer-option")).toHaveCount(10);
  await expect(page.locator("#manufacturerSearch")).toBeVisible();
  await page.locator("#manufacturerSearch").fill("La Sportiva");
  await expect(page.locator("#manufacturerOptions .manufacturer-option")).toHaveText(["La Sportiva"]);
});

test("mapping uses cache on reload and reloads from DB on manual manufacturer change", async ({ page }) => {
  let mappingRequests = 0;
  await page.route("**/api/catalog-maker/mapping-sources**", async (route) => {
    mappingRequests += 1;
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        mapped: true,
        items: [{ key: "hudy", name: "Hudy", enabled: true }],
      }),
    });
  });

  await page.addInitScript(() => {
    localStorage.setItem("catalog-maker:selected-manufacturer", "13");
    localStorage.setItem(
      "catalog-maker:mapping-cache",
      JSON.stringify({
        13: {
          mapped: true,
          items: [{ key: "cached-hudy", name: "Cached Hudy", enabled: true }],
        },
      }),
    );
  });

  await page.goto("/");
  await page.waitForFunction(() => document.querySelector("#manufacturerSelect")?.value === "13");
  await expect(page.locator("#mappingStatusText")).toContainText("Mapping OK");
  await page.waitForTimeout(300);
  expect(mappingRequests).toBe(0);

  await page.locator("#manufacturerSelect").evaluate((select) => {
    const nextOption = [...select.options].find((option) => option.value && option.value !== "13");
    select.value = nextOption?.value || "";
    select.dispatchEvent(new Event("change", { bubbles: true }));
  });
  await expect.poll(() => mappingRequests).toBe(1);

  await page.locator("#manufacturerSelect").evaluate((select) => {
    select.value = "13";
    select.dispatchEvent(new Event("change", { bubbles: true }));
  });
  await expect.poll(() => mappingRequests).toBe(2);
});

test("catalog maker remains usable on a narrow viewport", async ({ page }) => {
  await page.setViewportSize({ width: 390, height: 844 });
  await page.goto("/");

  await expect(page.locator("#sidebarDrawer")).toHaveAttribute("aria-hidden", "true");
  await page.locator("#sidebarOpenButton").click();
  await expect(page.locator("#findSourcesButton")).toBeVisible();
  await expect(page.locator("#settingsButton")).toBeVisible();
  await expect(page.locator("#sidebarOverlay")).toBeVisible();
  await expect(page.locator(".secondary-panel")).toHaveCSS("order", "1");
  await expect(page.locator(".main-workspace")).toHaveCSS("order", "2");
  await page.screenshot({ path: "test-results/catalog-maker-mobile.png", fullPage: true });
});

test("left controls open in a responsive sidebar drawer", async ({ page }) => {
  await page.goto("/");
  await expect(page.locator("#sidebarDrawer")).toBeVisible();
  await page.locator("#sidebarCloseButton").click();
  await expect(page.locator("#sidebarDrawer")).toHaveAttribute("aria-hidden", "true");
  await page.locator("#sidebarOpenButton").click();
  await expect(page.locator("#sidebarDrawer")).toBeVisible();
  await expect(page.locator("#sidebarOverlay")).toBeHidden();
});

test("workspace columns collapse and expand without leaving a gap", async ({ page }) => {
  await page.goto("/");
  await page.locator("#sidebarCloseButton").click();
  await expect(page.locator(".catalog-screen")).toHaveClass(/sidebar-collapsed/);
  const secondaryPanel = await page.locator(".secondary-panel").boundingBox();
  expect(secondaryPanel?.x).toBeGreaterThanOrEqual(44);

  await page.locator("#secondaryPanelToggle").click();
  await expect(page.locator(".catalog-screen")).toHaveClass(/secondary-collapsed/);
  await page.locator("#mainWorkspaceToggle").click();
  await expect(page.locator(".catalog-screen")).toHaveClass(/workspace-collapsed/);

  await page.locator("#secondaryPanelToggle").click();
  await page.locator("#mainWorkspaceToggle").click();
  await expect(page.locator(".catalog-screen")).not.toHaveClass(/secondary-collapsed/);
  await expect(page.locator(".catalog-screen")).not.toHaveClass(/workspace-collapsed/);
});

test("main workspace keeps a bottom horizontal scrollbar for wide data", async ({ page }) => {
  await page.setViewportSize({ width: 1061, height: 912 });
  await page.goto("/");

  const scrollState = await page.locator(".main-workspace .table-wrap").evaluate((element) => {
    const style = getComputedStyle(element);
    return {
      overflowX: style.overflowX,
      clientWidth: element.clientWidth,
      scrollWidth: element.scrollWidth,
    };
  });

  expect(scrollState.overflowX).toBe("auto");
  expect(scrollState.scrollWidth).toBeGreaterThan(scrollState.clientWidth);
});

test("picture candidates show source, dimensions, target assignment and save action", async ({ page }) => {
  await page.route("**/api/manufacturers", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({ items: [{ id: 13, name: "La Sportiva" }] }),
    });
  });
  await page.route("**/api/languages", async (route) => {
    await route.fulfill({ contentType: "application/json", body: JSON.stringify({ items: [] }) });
  });
  await page.route("**/api/catalog-maker/mapping-sources**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        mapped: true,
        items: [{ key: "hudy", name: "Hudy", enabled: true, health: "ok" }],
      }),
    });
  });
  await page.route("**/api/catalog-maker/product**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        product: {
          idProductCatalog: 135520,
          idProduct: 110927,
          idManufacturer: 13,
          codeManufacture: "LAS",
          supplierReference: "ZFHS099",
          name: "Aequilibrium Trek Woman GTX",
          position: 1,
          total: 380,
        },
        combinations: [
          {
            idProductCatalog: 110923,
            status: "SS25/Boty",
            color: "Carbon/Malibu Blue",
            combination: "36",
            ean13: "8058428191284",
            supplierStock: 1,
          },
        ],
      }),
    });
  });
  await page.route("**/api/catalog-maker/get-pictures**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        items: [
          {
            source: { key: "hudy", name: "Hudy", type: "supplier" },
            searchUrl: "https://www.hudy.cz/vyhledavani?q=8058428191284",
            candidates: [
              {
                rawTitle: "Aequilibrium Trek Woman GTX",
                url: "https://www.hudy.cz/product",
                pictures: [
                  "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='64'%3E%3Crect width='80' height='64' fill='red'/%3E%3C/svg%3E",
                  "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='90'%3E%3Crect width='120' height='90' fill='blue'/%3E%3C/svg%3E",
                ],
              },
            ],
          },
        ],
      }),
    });
  });
  let saveRequests = 0;
  await page.route("**/api/catalog-maker/save-picture", async (route) => {
    saveRequests += 1;
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        saved: true,
        candidateId: saveRequests,
        duplicateStatus: "unique",
      }),
    });
  });

  await page.addInitScript(() => {
    localStorage.setItem("catalog-maker:selected-manufacturer", "13");
  });
  await page.goto("/");
  await page.waitForFunction(() => document.querySelector("#manufacturerSelect")?.value === "13");
  await page.locator("#getPicturesButton").click();

  await expect(page.locator("#sourceModal")).toBeVisible();
  await expect(page.locator(".picture-candidate-title").first()).toHaveText("Hudy picture #1");
  await expect(page.locator(".picture-candidate-dimensions").first()).toContainText("too small, min 800 x 800");
  await expect(page.locator(".picture-candidate").first()).toHaveClass(/is-too-small/);
  await expect(page.locator(".picture-candidate-target").first()).toContainText("Target: color Carbon/Malibu Blue");
  await expect(page.locator(".picture-candidate-save")).toHaveCount(2);
  await expect(page.locator("#sourceBatchActionButton")).toBeVisible();
  await expect(page.locator("#sourceBatchActionButton")).toContainText("Save all");

  await page.locator("#sourceBatchActionButton").click();
  await expect(page.locator(".picture-candidate-save")).toHaveText(["Saved", "Saved"]);
  expect(saveRequests).toBe(2);
});

test("source candidates can fetch all pictures before saving candidates", async ({ page }) => {
  await page.route("**/api/manufacturers", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({ items: [{ id: 13, name: "La Sportiva" }] }),
    });
  });
  await page.route("**/api/languages", async (route) => {
    await route.fulfill({ contentType: "application/json", body: JSON.stringify({ items: [] }) });
  });
  await page.route("**/api/catalog-maker/mapping-sources**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        mapped: true,
        items: [{ key: "hudy", name: "Hudy", enabled: true, health: "ok" }],
      }),
    });
  });
  await page.route("**/api/catalog-maker/product**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        product: {
          idProductCatalog: 135520,
          idProduct: 110927,
          idManufacturer: 13,
          codeManufacture: "LAS",
          supplierReference: "ZFHS099",
          name: "Aequilibrium Trek Woman GTX",
          position: 1,
          total: 380,
        },
        combinations: [
          {
            idProductCatalog: 110923,
            status: "SS25/Boty",
            color: "Carbon/Malibu Blue",
            combination: "36",
            ean13: "8058428191284",
            supplierStock: 1,
          },
        ],
      }),
    });
  });
  await page.route("**/api/catalog-maker/find-sources**", async (route) => {
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        items: [
          {
            status: "found",
            source: { key: "hudy", name: "Hudy", type: "supplier" },
            candidates: [
              {
                title: "Direct Hudy / EAN: 8058428191284 / Color: Carbon/Malibu Blue",
                url: "https://www.hudy.cz/product",
              },
            ],
          },
        ],
      }),
    });
  });
  await page.route("**/api/catalog-maker/get-pictures**", async (route) => {
    expect(route.request().url()).not.toContain("sourceKey=");
    await route.fulfill({
      contentType: "application/json",
      body: JSON.stringify({
        items: [
          {
            source: { key: "hudy", name: "Hudy", type: "supplier" },
            candidates: [
              {
                rawTitle: "Aequilibrium Trek Woman GTX",
                url: "https://www.hudy.cz/product",
                pictures: [
                  "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='64'%3E%3Crect width='80' height='64' fill='red'/%3E%3C/svg%3E",
                ],
              },
            ],
          },
        ],
      }),
    });
  });

  await page.addInitScript(() => {
    localStorage.setItem("catalog-maker:selected-manufacturer", "13");
  });
  await page.goto("/");
  await page.waitForFunction(() => document.querySelector("#manufacturerSelect")?.value === "13");
  await page.locator("#findSourcesButton").click();

  await expect(page.locator("#sourceModal")).toBeVisible();
  await expect(page.locator("#sourceBatchActionButton")).toBeVisible();
  await expect(page.locator("#sourceBatchActionButton")).toContainText("Get all pictures");
  await page.locator("#sourceBatchActionButton").click();
  await expect(page.locator(".picture-candidate-title").first()).toHaveText("Hudy picture #1");
  await expect(page.locator("#sourceBatchActionButton")).toContainText("Save all");
});

test("uses one shared height for the top panel headers", async ({ page }) => {
  await page.goto("/");
  const heights = await page.locator("#sidebarDrawer .sidebar-drawer-header, .secondary-panel .column-header, .main-workspace .column-header").evaluateAll((elements) => elements.map((element) => Math.round(element.getBoundingClientRect().height)));
  expect(new Set(heights).size).toBe(1);
});

test("uses one shared visual style for the top panel headers", async ({ page }) => {
  await page.goto("/");
  const styles = await page.locator(".panel-header").evaluateAll((elements) => elements.map((element) => {
    const style = getComputedStyle(element);
    return [style.height, style.backgroundColor, style.borderBottomColor, style.fontSize, style.fontWeight, style.paddingLeft, style.paddingRight];
  }));
  expect(new Set(styles.map((style) => JSON.stringify(style))).size).toBe(1);
});

test("keeps the top panel headers on one baseline", async ({ page }) => {
  await page.goto("/");
  const positions = await page.locator(".panel-header").evaluateAll((elements) => elements.map((element) => {
    const rect = element.getBoundingClientRect();
    return [rect.top, rect.height];
  }));
  expect(new Set(positions.map((position) => JSON.stringify(position))).size).toBe(1);
  expect(positions[0][0]).toBe(0);
});

test("uses one shared visual style for panel controls", async ({ page }) => {
  await page.goto("/");
  const styles = await page.locator("#sidebarCloseButton, #secondaryPanelToggle, #mainWorkspaceToggle").evaluateAll((elements) => elements.map((element) => {
    const style = getComputedStyle(element);
    return [style.width, style.height, style.borderColor, style.backgroundColor, style.borderRadius];
  }));
  expect(new Set(styles.map((style) => JSON.stringify(style))).size).toBe(1);
});

test("theme toggle switches and persists dark mode", async ({ page }) => {
  await page.goto("/");
  await page.evaluate(() => localStorage.clear());
  await page.reload();
  await expect(page.locator("html")).not.toHaveClass(/(?:^| )dark(?: |$)/);
  const lightPanelBackground = await page.locator("#sidebarDrawer").evaluate((element) => getComputedStyle(element).backgroundColor);

  await page.locator("#themeToggle").click();
  await expect(page.locator("html")).toHaveClass(/(?:^| )dark(?: |$)/);
  await expect(page.locator("#themeToggle")).toHaveText("Light theme");
  const darkPanelBackground = await page.locator("#sidebarDrawer").evaluate((element) => getComputedStyle(element).backgroundColor);
  expect(darkPanelBackground).not.toBe(lightPanelBackground);

  await page.locator("#settingsButton").click();
  await page.locator("#darkContrastSelect").selectOption("high");
  await expect(page.locator("html")).toHaveClass(/contrast-dark-high/);

  await page.reload();
  await expect(page.locator("html")).toHaveClass(/(?:^| )dark(?: |$)/);
});
