import { readFileSync } from "node:fs";
import { describe, expect, it, vi } from "vitest";
import { autodoc } from "../src/adapters/autodoc.js";
import { normalizeQuery } from "../src/core/normalize.js";
import { OfferSchema, type FetchContext } from "../src/core/types.js";

const canonicalize = (v: string): string => v.toUpperCase().replace(/[^A-Z0-9]/g, "");
const html = readFileSync("fixtures/autodoc/0986452041.html", "utf-8");

describe("autodoc adapter (fixture: 0986452041, recorded 2026-07-12 via resident browser)", () => {
  const offers = autodoc.parse(html, normalizeQuery("0986452041")!);

  it("finds the product cards", () => {
    expect(offers.length).toBe(20);
  });

  it("waits for a result card before serializing the browser DOM", async () => {
    const fetchPageHtml = vi.fn().mockResolvedValue(html);
    const ctx = { browser: { fetchPageHtml } } as unknown as FetchContext;

    await autodoc.fetchRaw(normalizeQuery("0986452041")!, ctx);

    expect(fetchPageHtml).toHaveBeenCalledWith(
      "autodoc",
      "https://www.autodoc.lv/search?keyword=0986452041",
      { waitForSelector: ".listing-item[data-article-id]" },
    );
  });

  it("every offer passes schema validation", () => {
    for (const o of offers) expect(() => OfferSchema.parse(o)).not.toThrow();
  });

  it("surfaces the searched BOSCH part as an exact-number match", () => {
    const bosch = offers.find((o) => canonicalize(o.partNumber) === "0986452041");
    expect(bosch).toBeDefined();
    expect(bosch!.brand).toBe("BOSCH");
    expect(bosch!.partNumber).toBe("0 986 452 041");
    expect(bosch!.priceEur).toBe(5.99);
    expect(bosch!.availability).toBe("Ir noliktavā");
    expect(bosch!.url).toBe("https://www.autodoc.lv/bosch/1163417");
  });

  it("extracts image and spec attributes without echoing the part number row", () => {
    const bosch = offers.find((o) => canonicalize(o.partNumber) === "0986452041")!;
    expect(bosch.imageUrl).toBe("https://media.autodoc.de/360_photos/1163417/preview.jpg");
    expect(bosch.attributes).toContainEqual({ label: "Augstums", value: "87" });
    expect(bosch.attributes.some((a) => a.label === "Preces numurs")).toBe(false);
  });

  it("includes cross-brand analogues with their own part numbers", () => {
    const brands = new Set(offers.map((o) => o.brand));
    expect(brands.size).toBeGreaterThan(1);
    const parts = new Set(offers.map((o) => canonicalize(o.partNumber)));
    expect(parts.size).toBeGreaterThan(1);
  });
});
