import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import test from "node:test";

import {
  assertCloudWebDistFresh,
  buildCloudWebDist,
  cloudWebDistAliasFiles,
  inspectCloudWebDistFreshness
} from "./dist-contract.ts";

test("Cloud Web dist build emits Vite assets and route aliases", async () => {
  const rootDir = makeCloudWebFixture();

  try {
    const distDir = await buildCloudWebDist(rootDir);
    assert.equal(distDir, path.join(rootDir, "dist"));

    const html = read(path.join(distDir, "index.html"));
    assert.match(html, /<div id="root"><\/div>/u);
    assert.match(html, /src="\/app\.js"/u);
    assert.match(html, /href="\/assets\/index\.css"/u);
    assert.match(html, /href="\/assets\/favicon\.svg"/u);
    assert.match(read(path.join(distDir, "app.js")), /fixture-app/u);
    assert.match(read(path.join(distDir, "assets/index.css")), /fixture-shell/u);
    assert.equal(read(path.join(distDir, "help.md")), read(path.join(rootDir, "help.md")));

    for (const relativePath of cloudWebDistAliasFiles) {
      assert.equal(read(path.join(distDir, relativePath)), html, `alias asset ${relativePath}`);
    }

    const freshness = await assertCloudWebDistFresh(rootDir);
    assert.equal(freshness.status, "pass");
    assert.deepEqual(freshness.mismatches, []);
  } finally {
    fs.rmSync(rootDir, { recursive: true, force: true });
  }
});

test("Cloud Web dist freshness reports stale generated app asset", async () => {
  const rootDir = makeCloudWebFixture();

  try {
    await buildCloudWebDist(rootDir);
    fs.writeFileSync(path.join(rootDir, "src/App.tsx"), "export function App() { return 'changed-app'; }\n");

    const freshness = await inspectCloudWebDistFreshness(rootDir);
    assert.equal(freshness.status, "blocked");
    assert.ok(freshness.mismatches.includes("app.js"));
    assert.equal(freshness.files.find((file) => file.path === "app.js")?.status, "mismatch");
  } finally {
    fs.rmSync(rootDir, { recursive: true, force: true });
  }
});

function makeCloudWebFixture(): string {
  const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "hwlab-cloud-web-dist-"));
  write(rootDir, "index.html", [
    "<!doctype html>",
    "<html lang=\"zh-CN\">",
    "  <head>",
    "    <meta charset=\"UTF-8\" />",
    "    <link rel=\"icon\" href=\"/favicon.svg\" type=\"image/svg+xml\" />",
    "    <title>fixture</title>",
    "  </head>",
    "  <body><div id=\"root\"></div><script type=\"module\" src=\"/src/main.tsx\"></script></body>",
    "</html>",
    ""
  ].join("\n"));
  write(rootDir, "vite.config.ts", [
    "export default {",
    "  build: {",
    "    outDir: 'dist',",
    "    emptyOutDir: true,",
    "    rollupOptions: { output: { entryFileNames: 'app.js', chunkFileNames: 'assets/[name].js', assetFileNames: 'assets/[name][extname]' } }",
    "  }",
    "};",
    ""
  ].join("\n"));
  write(rootDir, "src/main.tsx", "import './styles/workbench.css';\nimport { App } from './App';\nconsole.log('fixture-app', App());\n");
  write(rootDir, "src/App.tsx", "export function App() { return 'fixture-app'; }\n");
  write(rootDir, "src/styles/workbench.css", ".fixture-shell { color: #0f766e; }\n");
  write(rootDir, "favicon.svg", "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1 1\"><rect width=\"1\" height=\"1\"/></svg>\n");
  write(rootDir, "help.md", "# fixture help\n");
  return rootDir;
}

function write(rootDir: string, relativePath: string, text: string): void {
  const filePath = path.join(rootDir, relativePath);
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, text);
}

function read(filePath: string): string {
  return fs.readFileSync(filePath, "utf8");
}
