import assert from "node:assert/strict";
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import test from "node:test";
import { tmpdir } from "node:os";

import { projectGeneratedImageItem, projectGeneratedImages } from "./generated-images.js";

test("projects workspace Markdown images through durable opaque attachment URLs", async () => {
  const root = await mkdtemp(join(tmpdir(), "code-remote-manager-generated-"));
  const workspacePath = join(root, "workspace");
  const dataDir = join(root, "data");
  const sourcePath = join(workspacePath, "art", "candidate.png");
  await mkdir(join(workspacePath, "art"), { recursive: true });
  await writeFile(sourcePath, Buffer.from([0x89, 0x50, 0x4e, 0x47]));
  const session = { id: "session-1", attachments: [] };

  try {
    const text = `Preview\n![candidate](${sourcePath.replaceAll("\\", "/")})`;
    const projected = projectGeneratedImages({ text, session, workspacePath, dataDir });

    assert.match(projected, /^Preview\n!\[candidate\]\(\/api\/sessions\/session-1\/attachments\/generated-[a-f0-9]{24}\)$/);
    assert.equal(projected.includes(workspacePath), false);
    assert.equal(session.attachments.length, 1);
    assert.equal(session.attachments[0].name, "Generated image.png");
    assert.deepEqual(await readFile(session.attachments[0].path), Buffer.from([0x89, 0x50, 0x4e, 0x47]));

    assert.equal(projectGeneratedImages({ text, session, workspacePath, dataDir }), projected);
    assert.equal(session.attachments.length, 1);
  } finally {
    await rm(root, { recursive: true, force: true });
  }
});

test("does not project images outside the selected workspace", async () => {
  const root = await mkdtemp(join(tmpdir(), "code-remote-manager-generated-outside-"));
  const workspacePath = join(root, "workspace");
  const outsidePath = join(root, "private.png");
  await mkdir(workspacePath, { recursive: true });
  await writeFile(outsidePath, "private");

  try {
    const text = `![private](${outsidePath.replaceAll("\\", "/")})`;
    assert.equal(projectGeneratedImages({
      text,
      session: { id: "session-1", attachments: [] },
      workspacePath,
      dataDir: join(root, "data")
    }), text);
  } finally {
    await rm(root, { recursive: true, force: true });
  }
});

test("copies app-server generated images outside the workspace to opaque attachments", async () => {
  const root = await mkdtemp(join(tmpdir(), "code-remote-manager-generated-item-"));
  const sourcePath = join(root, "codex-output.png");
  const dataDir = join(root, "data");
  await writeFile(sourcePath, Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]));
  const session = { id: "session-image", attachments: [] };

  try {
    const images = projectGeneratedImageItem({
      item: { type: "imageGeneration", savedPath: sourcePath },
      session,
      dataDir
    });

    assert.equal(images.length, 1);
    assert.match(images[0].url, /^\/api\/sessions\/session-image\/attachments\/generated-[a-f0-9]{24}$/);
    assert.equal(JSON.stringify(images).includes(sourcePath), false);
    assert.equal(session.attachments[0].mimeType, "image/png");
  } finally {
    await rm(root, { recursive: true, force: true });
  }
});

test("rejects remote and invalid generated image sources", () => {
  const session = { id: "session-image", attachments: [] };
  assert.deepEqual(projectGeneratedImageItem({
    item: { type: "imageGeneration", result: "https://example.com/private.png" },
    session,
    dataDir: "unused"
  }), []);
  assert.deepEqual(projectGeneratedImageItem({
    item: { type: "dynamicToolCall", contentItems: [{ type: "inputImage", imageUrl: "data:text/plain;base64,c2VjcmV0" }] },
    session,
    dataDir: "unused"
  }), []);
});
