import assert from "node:assert/strict";
import test from "node:test";

import { artifactHeaders, resolveArtifactRoute } from "./artifact-routes.js";

test("resolves only opaque session artifact GET routes", async () => {
  const artifact = { data: Buffer.from("safe"), name: "preview.html", mimeType: "text/html", size: 4 };
  const calls = [];
  const result = await resolveArtifactRoute(
    { method: "GET" },
    new URL("http://localhost/sessions/session-1/artifacts/artifact-abc"),
    {
      getSession: (id) => ({ id }),
      getArtifact: async (session, id) => {
        calls.push({ session: session.id, id });
        return artifact;
      }
    }
  );

  assert.deepEqual(calls, [{ session: "session-1", id: "artifact-abc" }]);
  assert.deepEqual(result, { status: 200, artifact });
  assert.equal(await resolveArtifactRoute({ method: "POST" }, new URL("http://localhost/sessions/session-1/artifacts/artifact-abc"), {}), null);
  assert.equal(await resolveArtifactRoute({ method: "GET" }, new URL("http://localhost/sessions/session-1/files"), {}), null);
});

test("passes a bundled HTML resource path to the backend artifact resolver", async () => {
  const calls = [];
  await resolveArtifactRoute(
    { method: "GET" },
    new URL("http://localhost/sessions/session-1/artifacts/artifact-abc/styles/site.css"),
    {
      getSession: () => ({ id: "session-1" }),
      getArtifact: async (_session, id, resourcePath) => {
        calls.push({ id, resourcePath });
        return { data: Buffer.from("css"), name: "site.css", mimeType: "text/css", size: 3 };
      }
    }
  );
  assert.deepEqual(calls, [{ id: "artifact-abc", resourcePath: "styles/site.css" }]);
});

test("HTML artifact headers enforce an isolated no-network preview", () => {
  const headers = artifactHeaders({ name: "preview.html", mimeType: "text/html", size: 42 });

  assert.equal(headers["content-type"], "text/html; charset=utf-8");
  assert.equal(headers["x-content-type-options"], "nosniff");
  assert.equal(headers["content-length"], "42");
  assert.match(headers["content-security-policy"], /default-src 'none'/);
  assert.match(headers["content-security-policy"], /connect-src 'none'/);
  assert.match(headers["content-security-policy"], /script-src 'none'/);
  assert.match(headers["content-security-policy"], /form-action 'none'/);
  assert.match(headers["content-security-policy"], /sandbox(?:;|$)/);
  assert.doesNotMatch(headers["content-security-policy"], /allow-scripts/);
  assert.equal(headers["content-disposition"], 'inline; filename="preview.html"');
});

test("download headers strip unsafe filename characters", () => {
  const headers = artifactHeaders({ name: 'report\r\n".zip', mimeType: "application/zip", size: 7 });
  assert.equal(headers["content-disposition"], 'attachment; filename="report___.zip"');
});

test("SVG artifact headers prohibit script execution and external loading", () => {
  const headers = artifactHeaders({ name: "diagram.svg", mimeType: "image/svg+xml", size: 100 });
  assert.match(headers["content-security-policy"], /default-src 'none'/);
  assert.match(headers["content-security-policy"], /sandbox(?:;|$)/);
  assert.doesNotMatch(headers["content-security-policy"], /allow-scripts/);
});
