// src/lib/semantic/fetch.test.ts
import { describe, expect, test } from "bun:test";
import { fetchSemanticHtml, MOBILE_UA } from "./fetch";

function fakeFetch(
  body: string,
  init: { status?: number; contentType?: string; url?: string } = {},
) {
  return (async (_input: RequestInfo | URL, reqInit?: RequestInit) => {
    const res = new Response(body, {
      status: init.status ?? 200,
      headers: {
        "content-type": init.contentType ?? "text/html; charset=utf-8",
      },
    });
    Object.defineProperty(res, "url", {
      value: init.url ?? "https://ex.com/final",
    });
    // expose les headers envoyés pour l'assertion UA
    (globalThis as Record<string, unknown>).__lastReqInit = reqInit;
    return res;
  }) as typeof fetch;
}

describe("fetchSemanticHtml", () => {
  test("renvoie html + finalUrl et envoie l'UA mobile", async () => {
    const out = await fetchSemanticHtml(
      "https://ex.com/a",
      fakeFetch("<html>ok</html>"),
    );
    expect(out?.html).toContain("ok");
    expect(out?.finalUrl).toBe("https://ex.com/final");
    const init = (globalThis as Record<string, unknown>)
      .__lastReqInit as RequestInit;
    expect(new Headers(init.headers).get("user-agent")).toBe(MOBILE_UA);
  });

  test("null sur non-HTML et sur statut != 2xx", async () => {
    expect(
      await fetchSemanticHtml(
        "https://ex.com/a",
        fakeFetch("{}", { contentType: "application/json" }),
      ),
    ).toBeNull();
    expect(
      await fetchSemanticHtml(
        "https://ex.com/a",
        fakeFetch("nope", { status: 404 }),
      ),
    ).toBeNull();
  });

  test("null quand le fetcher throw", async () => {
    const throwing = (async () => {
      throw new Error("boom");
    }) as unknown as typeof fetch;
    expect(await fetchSemanticHtml("https://ex.com/a", throwing)).toBeNull();
  });
});
