import assert from "node:assert/strict";
import { access, mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import test from "node:test";
import { packagePages } from "../../scripts/package-pages.mjs";

test("packages client assets and the complete server module graph", async () => {
  const root = await mkdtemp(join(tmpdir(), "hearbooks-pages-"));
  const client = join(root, "client");
  const server = join(root, "server");
  const output = join(root, "pages");
  try {
    await mkdir(join(client, "_next"), { recursive: true });
    await mkdir(join(server, "ssr"), { recursive: true });
    await writeFile(join(client, "index.html"), "HearBooks");
    await writeFile(join(client, "_next", "asset.js"), "asset");
    await writeFile(join(server, "index.js"), "import './ssr/route.js';");
    await writeFile(join(server, "ssr", "route.js"), "export default true;");

    const result = await packagePages({
      clientDirectory: client,
      serverDirectory: server,
      outputDirectory: output,
    });
    assert.equal(result.workerEntry, join(output, "_worker.js"));
    assert.equal(result.routesFile, join(output, "_routes.json"));
    assert.equal(await readFile(join(output, "index.html"), "utf8"), "HearBooks");
    assert.match(await readFile(result.workerEntry, "utf8"), /\.\/server\/index\.js/);
    assert.deepEqual(
      JSON.parse(await readFile(result.routesFile, "utf8")),
      { version: 1, include: ["/*"], exclude: ["/_next/static/*"] },
    );
    assert.equal(await readFile(join(output, "server", "ssr", "route.js"), "utf8"), "export default true;");
  } finally {
    await rm(root, { recursive: true, force: true });
  }
});

test("refuses a build without the vinext worker entry", async () => {
  const root = await mkdtemp(join(tmpdir(), "hearbooks-pages-missing-"));
  try {
    const client = join(root, "client");
    const server = join(root, "server");
    await mkdir(client);
    await mkdir(server);
    await assert.rejects(
      packagePages({ clientDirectory: client, serverDirectory: server, outputDirectory: join(root, "pages") }),
      /server entry/i,
    );
  } finally {
    await rm(root, { recursive: true, force: true });
  }
});

test("does not copy Vinext's Worker deployment config into the Pages worker directory", async () => {
  const root = await mkdtemp(join(tmpdir(), "hearbooks-pages-worker-config-"));
  try {
    const client = join(root, "client");
    const server = join(root, "server");
    const output = join(root, "pages");
    await mkdir(client);
    await mkdir(server);
    await writeFile(join(server, "index.js"), "export default {};");
    await writeFile(join(server, "wrangler.json"), "{\\\"assets\\\": {\\\"directory\\\": \\\"../client\\\"}}");

    await packagePages({ clientDirectory: client, serverDirectory: server, outputDirectory: output });

    await assert.rejects(access(join(output, "server", "wrangler.json")));
  } finally {
    await rm(root, { recursive: true, force: true });
  }
});

test("refuses every output path that overlaps a source tree", async () => {
  const root = await mkdtemp(join(tmpdir(), "hearbooks-pages-overlap-"));
  const client = join(root, "client");
  const server = join(root, "server");
  try {
    await mkdir(client);
    await mkdir(server);
    await writeFile(join(server, "index.js"), "export default {};");
    for (const outputDirectory of [client, server, root, join(client, "pages")]) {
      await assert.rejects(
        packagePages({ clientDirectory: client, serverDirectory: server, outputDirectory }),
        /overlap/i,
      );
    }
  } finally {
    await rm(root, { recursive: true, force: true });
  }
});
