import assert from "node:assert/strict";
import test from "node:test";
import { AssetInliner, splitSrcset } from "../src/asset-inliner.mjs";
import { findExternalAssetRefs } from "../src/archiver.mjs";

test("inlines real srcset attributes without reading escaped src text from srcdoc", async () => {
  const fetched = [];
  const inliner = new AssetInliner();
  inliner.fetchAsset = async (rawUrl) => {
    fetched.push(rawUrl);
    return {
      bytes: Buffer.from("asset"),
      contentType: "image/png"
    };
  };

  const html = `
    <img srcset="/small.png 1x, /large.png 2x">
    <iframe srcdoc="&lt;script src=&quot;https://js.stripe.com/v3/foo.js&quot;&gt;&lt;/script&gt;&lt;img src=&quot;/nested.png&quot;&gt;"></iframe>
  `;

  const output = await inliner.inlineHtml(html, "https://example.com/article");

  assert.deepEqual(fetched.sort(), [
    "https://example.com/large.png",
    "https://example.com/nested.png",
    "https://example.com/small.png",
  ]);
  assert.doesNotMatch(output, /js\.stripe\.com/);
  assert.equal(inliner.warnings.length, 0);
});

test("external asset reporting ignores escaped nested attributes inside srcdoc", () => {
  const refs = findExternalAssetRefs(`
    <iframe srcdoc="&lt;img src=&quot;https://tracker.example/pixel.gif&quot;&gt;"></iframe>
    <img src="https://cdn.example/picture.jpg">
  `);

  assert.deepEqual(refs, ["https://cdn.example/picture.jpg"]);
});

test("srcset parsing keeps image CDN transform commas inside URLs", async () => {
  assert.deepEqual(splitSrcset([
    "https://media.example/photos/id/master/w_120,c_limit/photo.jpg 120w",
    "https://media.example/photos/id/master/w_240,c_limit/photo.jpg 240w"
  ].join(", ")), [
    "https://media.example/photos/id/master/w_120,c_limit/photo.jpg 120w",
    "https://media.example/photos/id/master/w_240,c_limit/photo.jpg 240w"
  ]);

  const fetched = [];
  const inliner = new AssetInliner();
  inliner.fetchAsset = async (rawUrl) => {
    fetched.push(rawUrl);
    return {
      bytes: Buffer.from("asset"),
      contentType: "image/jpeg"
    };
  };

  await inliner.inlineSrcset(
    "https://media.example/photos/id/master/w_120,c_limit/photo.jpg 120w, https://media.example/photos/id/master/w_240,c_limit/photo.jpg 240w",
    "https://example.com/article"
  );

  assert.deepEqual(fetched, [
    "https://media.example/photos/id/master/w_120,c_limit/photo.jpg",
    "https://media.example/photos/id/master/w_240,c_limit/photo.jpg"
  ]);
});

test("external asset reporting parses srcset-like attributes without splitting URL commas", () => {
  const refs = findExternalAssetRefs(`
    <img srcset="data:image/gif;base64,R0lGODlhAQABAAAAACw= 1x, https://cdn.example/image.jpg 2x">
    <link rel="preload" as="image" imagesrcset="https://media.example/photos/id/master/w_120,c_limit/photo.jpg 120w, https://media.example/photos/id/master/w_240,c_limit/photo.jpg 240w">
  `);

  assert.deepEqual(refs, [
    "https://cdn.example/image.jpg",
    "https://media.example/photos/id/master/w_120,c_limit/photo.jpg",
    "https://media.example/photos/id/master/w_240,c_limit/photo.jpg"
  ]);
});

test("removes image preload srcsets when the link has no href", async () => {
  const fetched = [];
  const inliner = new AssetInliner();
  inliner.fetchAsset = async (rawUrl) => {
    fetched.push(rawUrl);
    return {
      bytes: Buffer.from("asset"),
      contentType: "image/jpeg"
    };
  };

  const output = await inliner.inlineHtml(`
    <link rel="preload" as="image" imagesrcset="https://media.example/photos/id/master/w_120,c_limit/photo.jpg 120w, https://media.example/photos/id/master/w_240,c_limit/photo.jpg 240w">
  `, "https://example.com/article");

  assert.deepEqual(fetched, []);
  assert.doesNotMatch(output, /https:\/\/media\.example/);
  assert.doesNotMatch(output, /imagesrcset/);
  assert.deepEqual(findExternalAssetRefs(output), []);
});

test("drops responsive image candidates after snapshot src is available", async () => {
  const fetched = [];
  const inliner = new AssetInliner();
  inliner.fetchAsset = async (rawUrl) => {
    fetched.push(rawUrl);
    return {
      bytes: Buffer.from("asset"),
      contentType: "image/jpeg"
    };
  };

  const output = await inliner.inlineHtml(`
    <picture>
      <source srcset="/small.webp 640w, /large.webp 1280w" type="image/webp">
      <img src="/selected.jpg" srcset="/small.jpg 640w, /large.jpg 1280w">
    </picture>
  `, "https://example.com/article");

  assert.deepEqual(fetched, ["https://example.com/selected.jpg"]);
  assert.doesNotMatch(output, /srcset=/);
  assert.deepEqual(findExternalAssetRefs(output), []);
});

test("asset inliner skips URLs blocked by the filter hook", async () => {
  const blocked = [];
  const inliner = new AssetInliner({
    shouldBlockAsset: (url, resourceType) => {
      blocked.push([url, resourceType]);
      return true;
    }
  });

  const output = await inliner.inlineHtml(`
    <link rel="stylesheet" href="https://ads.example/ad.css">
    <img src="https://ads.example/ad.png">
  `, "https://publisher.example/article");

  assert.doesNotMatch(output, /ad\.css/);
  assert.match(output, /data:image\/gif;base64/);
  assert.deepEqual(blocked, [
    ["https://ads.example/ad.css", "stylesheet"],
    ["https://ads.example/ad.png", "image"]
  ]);
});
