import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { createServer } from "node:http";
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { promisify } from "node:util";
import test from "node:test";

const execFileAsync = promisify(execFile);
const installer = new URL("../server/assets/foundry-agent-npm/bin/nodedc-foundry-codex-agent.mjs", import.meta.url);

async function listen(server) {
  await new Promise((resolve, reject) => {
    server.once("error", reject);
    server.listen(0, "127.0.0.1", resolve);
  });
  return `http://127.0.0.1:${server.address().port}`;
}

test("Foundry installer preserves unrelated MCP entries and installs two independent servers", async () => {
  let baseUrl = "";
  const server = createServer(async (request, response) => {
    if (request.url === "/api/foundry-agent/v1/setup/redeem") {
      response.writeHead(200, { "content-type": "application/json" });
      response.end(JSON.stringify({
        ok: true,
        foundry: { serverName: "nodedc_module_foundry", mcpUrl: `${baseUrl}/foundry-mcp`, token: "foundry-device-token" },
        ontology: { serverName: "nodedc_ontology", mcpUrl: `${baseUrl}/ontology-mcp`, token: "ontology-device-token", readOnly: true },
      }));
      return;
    }
    if (request.url === "/foundry-mcp" || request.url === "/ontology-mcp") {
      const chunks = [];
      for await (const chunk of request) chunks.push(chunk);
      const message = JSON.parse(Buffer.concat(chunks).toString("utf8"));
      const tools = request.url === "/foundry-mcp"
        ? [{ name: "foundry_status" }, { name: "foundry_create_application" }]
        : [{ name: "ontology_status" }, { name: "ontology_search" }];
      response.writeHead(200, { "content-type": "application/json" });
      response.end(JSON.stringify({
        jsonrpc: "2.0",
        id: message.id,
        result: message.method === "tools/list"
          ? { tools }
          : { protocolVersion: "2025-06-18", capabilities: { tools: {} }, serverInfo: { name: "test", version: "1" } },
      }));
      return;
    }
    response.writeHead(404);
    response.end();
  });
  baseUrl = await listen(server);
  const codexHome = await mkdtemp(path.join(os.tmpdir(), "nodedc-foundry-installer-"));
  await mkdir(codexHome, { recursive: true });
  const original = [
    "model = \"gpt-5\"",
    "",
    "[mcp_servers.nodedc_engine_agent]",
    "url = \"https://engine.example/mcp\"",
    "",
    "[mcp_servers.nodedc_module_foundry]",
    "url = \"https://stale.example/foundry\"",
    "",
    "[mcp_servers.nodedc_ontology]",
    "url = \"https://stale.example/ontology\"",
    "",
  ].join("\n");
  await writeFile(path.join(codexHome, "config.toml"), original, "utf8");
  try {
    const result = await execFileAsync(process.execPath, [installer.pathname, "--server", baseUrl, "--code", "test-code", "--codex-home", codexHome]);
    assert.match(result.stdout, /Foundry MCP smoke tools: 2/);
    assert.match(result.stdout, /Ontology MCP smoke tools: 2/);

    const config = await readFile(path.join(codexHome, "config.toml"), "utf8");
    assert.match(config, /\[mcp_servers\.nodedc_engine_agent\]/);
    assert.equal((config.match(/\[mcp_servers\.nodedc_module_foundry\]/g) || []).length, 1);
    assert.equal((config.match(/\[mcp_servers\.nodedc_ontology\]/g) || []).length, 1);
    assert.match(config, new RegExp(`${baseUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\/foundry-mcp`));
    assert.match(config, /Bearer foundry-device-token/);
    assert.match(config, /Bearer ontology-device-token/);
    assert.equal(config.includes("stale.example"), false);

    const backup = await readFile(path.join(codexHome, "config.toml.nodedc-foundry-agent.bak"), "utf8");
    assert.equal(backup, original);
    const skill = await readFile(path.join(codexHome, "skills", "foundry-context", "SKILL.md"), "utf8");
    assert.match(skill, /nodedc_module_foundry/);
    assert.match(skill, /nodedc_ontology/);

    const doctor = await execFileAsync(process.execPath, [installer.pathname, "doctor", "--codex-home", codexHome]);
    assert.match(doctor.stdout, /install is present/);
  } finally {
    await new Promise((resolve) => server.close(resolve));
    await rm(codexHome, { recursive: true, force: true });
  }
});
