// src/lib/semantic/render.test.ts
import { describe, expect, test } from "bun:test";
import {
  chromeLocalRender,
  parseDevtoolsWsUrl,
  resolveRenderProvider,
} from "./render";

describe("resolveRenderProvider", () => {
  test("chemin explicite prioritaire quand le fichier existe", async () => {
    const provider = resolveRenderProvider(
      { chromePath: "/opt/custom/chrome" },
      { exists: (p) => p === "/opt/custom/chrome" },
    );
    expect(provider).not.toBeNull();
  });

  test("null quand le chemin explicite n'existe pas (pas de fallback auto)", () => {
    const provider = resolveRenderProvider(
      { chromePath: "/opt/missing/chrome" },
      { exists: () => false, platform: "darwin" },
    );
    expect(provider).toBeNull();
  });

  test("auto-détection macOS quand aucun chemin explicite", () => {
    const seen: string[] = [];
    const provider = resolveRenderProvider(
      {},
      {
        platform: "darwin",
        exists: (p) => {
          seen.push(p);
          return (
            p === "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
          );
        },
      },
    );
    expect(provider).not.toBeNull();
    expect(seen).toContain(
      "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
    );
  });

  test("auto-détection Linux quand aucun chemin explicite", () => {
    const provider = resolveRenderProvider(
      {},
      {
        platform: "linux",
        exists: (p) => p === "/usr/bin/chromium",
      },
    );
    expect(provider).not.toBeNull();
  });

  test("null si rien n'est trouvé", () => {
    const provider = resolveRenderProvider(
      {},
      { platform: "darwin", exists: () => false },
    );
    expect(provider).toBeNull();
  });
});

describe("parseDevtoolsWsUrl", () => {
  test("extrait l'URL WS depuis la ligne stderr de Chrome", () => {
    const chunk =
      "[12345:0x0] DEBUG DevTools listening on ws://127.0.0.1:54321/devtools/browser/abc-123-def\n";
    expect(parseDevtoolsWsUrl(chunk)).toBe(
      "ws://127.0.0.1:54321/devtools/browser/abc-123-def",
    );
  });

  test("null quand la ligne n'est pas encore présente dans le chunk", () => {
    expect(parseDevtoolsWsUrl("Starting Chrome...\n")).toBeNull();
  });

  test("trouve la ligne même noyée dans d'autres logs", () => {
    const chunk = [
      "[1:2] some other log line",
      "DevTools listening on ws://127.0.0.1:9999/devtools/browser/xyz",
      "[1:2] yet another log line",
    ].join("\n");
    expect(parseDevtoolsWsUrl(chunk)).toBe(
      "ws://127.0.0.1:9999/devtools/browser/xyz",
    );
  });
});

// Smoke test réel : nécessite un vrai Chrome sur la machine. Gaté par
// RENDER_TESTS=1 pour ne jamais tourner en CI sans navigateur disponible.
// La preuve du rendu : la page ne contient le texte "hydraté par JS" qu'après
// exécution du <script> inline — un simple fetch HTTP ne l'aurait jamais vu.
const runSmoke = process.env.RENDER_TESTS === "1";

describe("chromeLocalRender (smoke réel)", () => {
  test.skipIf(!runSmoke)(
    "rend le JS d'une page data: et capture le HTML hydraté",
    async () => {
      const chromePath = resolveChromePathForSmoke();
      const html =
        "<html><body><div id=x></div><script>document.getElementById('x').textContent='hydraté par JS'</script></body></html>";
      // charset=utf-8 explicite + percent-encodage : RFC 2397 suppose
      // US-ASCII par défaut, les octets UTF-8 bruts (accents) seraient
      // sinon mal réinterprétés par le parseur d'URL de Chrome.
      const dataUrl = `data:text/html;charset=utf-8,${encodeURIComponent(html)}`;

      const result = await chromeLocalRender(chromePath, dataUrl);

      expect(result).not.toBeNull();
      expect(result?.html).toContain("hydraté par JS");
    },
    25_000,
  );
});

function resolveChromePathForSmoke(): string {
  const explicit = process.env.CHROME_PATH;
  if (explicit) return explicit;
  return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
}
