import test from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { temporaryDirectory, createProductionServer, productionPort } from "./host-lib.mjs";

test("production host port defaults safely and accepts a smoke-test override", () => {
  assert.equal(productionPort({}), 43111);
  assert.equal(productionPort({ CODE_REMOTE_MANAGER_PWA_PORT: "45231" }), 45231);
  assert.throws(() => productionPort({ CODE_REMOTE_MANAGER_PWA_PORT: "0" }), /Invalid production host port/);
  assert.throws(() => productionPort({ CODE_REMOTE_MANAGER_PWA_PORT: "not-a-port" }), /Invalid production host port/);
});

test("production host writes bounded seven-day logs through the retained logger", async () => {
  const source = await readFile(new URL("host.mjs", import.meta.url), "utf8");

  assert.match(source, /appendRetainedLog/);
  assert.match(source, /CODE_REMOTE_MANAGER_MANAGED_HOST: "1"/);
  assert.doesNotMatch(source, /async function writeSafeLog/);
});

test("production server serves the PWA and proxies only /api to loopback", async (t) => {
  const root = await temporaryDirectory();
  await import("node:fs/promises").then(({ writeFile }) => writeFile(join(root, "index.html"), "release-shell"));
  const backend = await import("node:http").then(({ createServer }) => createServer((req, res) => {
    res.end(`backend:${req.url}:${req.headers.origin ?? ""}`);
  }));
  await new Promise((resolve) => backend.listen(0, "127.0.0.1", resolve));
  const backendPort = backend.address().port;
  const server = createProductionServer({ publicDir: root, backendPort });
  await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
  t.after(() => { server.close(); backend.close(); });
  const port = server.address().port;

  assert.equal(await fetch(`http://127.0.0.1:${port}/`).then((r) => r.text()), "release-shell");
  assert.equal(await fetch(`http://127.0.0.1:${port}/api/health`, { headers: { origin: "https://localhost" } }).then((r) => r.text()), "backend:/health:https://localhost");
  assert.equal(server.address().address, "127.0.0.1");
});

test("desktop setup exposes prerequisite checks, folder selection, QR and diagnostics", async () => {
  const source = await readFile(new URL("SetupApp/MainForm.cs", import.meta.url), "utf8");
  assert.match(source, /Codex CLI/);
  assert.match(source, /Tailscale/);
  assert.match(source, /FolderBrowserDialog/);
  assert.match(source, /QRCodeGenerator/);
  assert.match(source, /config\.local\.json/);
  assert.match(source, /127\.0\.0\.1/);
});

test("desktop setup uses a bounded three-step wizard with contextual actions", async () => {
  const source = await readFile(new URL("SetupApp/MainForm.cs", import.meta.url), "utf8");
  assert.match(source, /필수 프로그램/);
  assert.match(source, /프로젝트 폴더/);
  assert.match(source, /휴대폰 연결/);
  assert.match(source, /ShowStep/);
  assert.match(source, /AutoScaleMode\.Dpi/);
  assert.match(source, /Visible = codexPath is null/);
  assert.match(source, /Visible = tailnetUrl is null/);
  assert.match(source, /IconBadge/);
  assert.match(source, /BackColor = Color\.Transparent/);
  assert.match(source, /refresh\.Visible = codexPath is null \|\| tailnetUrl is null/);
  assert.match(source, /MaximumSize = new Size\(360, 0\)/);
  assert.doesNotMatch(source, /AutoScroll = true/);
});

test("desktop setup defaults to English and offers an in-app Korean language switch", async () => {
  const source = await readFile(new URL("SetupApp/MainForm.cs", import.meta.url), "utf8");
  assert.match(source, /private UiLanguage language = UiLanguage\.English/);
  assert.match(source, /English/);
  assert.match(source, /한국어/);
  assert.match(source, /ApplyLanguage/);
  assert.match(source, /Code Remote Manager PC Setup/);
});

test("desktop setup uses versioned migration and keeps existing workspaces by default", async () => {
  const source = await readFile(new URL("SetupApp/MainForm.cs", import.meta.url), "utf8");
  assert.match(source, /ConfigurationMigration\.BuildCandidate/);
  assert.match(source, /BackendConfigurationValidator/);
  assert.match(source, /ConfigurationStore/);
  assert.match(source, /SaveConfigurationAsync/);
  assert.match(source, /hasExistingConfiguration \? string\.Empty/);
  assert.doesNotMatch(source, /File\.WriteAllText\(/);
});
