// A hub with a self-signed certificate: plain fetch refuses it, and the
// fetch that trusts the remote's CA file reaches it.
import { test } from "node:test";
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { mkdtempSync, readFileSync } from "node:fs";
import { createServer } from "node:https";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { fetchTrusting, HubClient } from "../out/hub.mjs";

test("a self-signed hub is reached with its CA file", async () => {
  const dir = mkdtempSync(join(tmpdir(), "hubtls-"));
  const key = join(dir, "key.pem");
  const cert = join(dir, "cert.pem");
  execFileSync("openssl", ["req", "-x509", "-newkey", "rsa:2048", "-nodes", "-keyout", key, "-out", cert, "-days", "1", "-subj", "/CN=127.0.0.1", "-addext", "subjectAltName=IP:127.0.0.1"], { stdio: "ignore" });
  const server = createServer({ key: readFileSync(key), cert: readFileSync(cert) }, (req, res) => {
    let body = "";
    req.on("data", (c) => (body += c));
    req.on("end", () => {
      if (req.url === "/api/v1/user") {
        res.writeHead(200, { "content-type": "application/json" });
        res.end(JSON.stringify({ username: "andy", auth: req.headers.authorization ?? "" }));
      } else if (req.url === "/echo") {
        res.writeHead(201, { "content-type": "application/json" });
        res.end(JSON.stringify({ method: req.method, body }));
      } else {
        res.writeHead(204);
        res.end();
      }
    });
  });
  await new Promise((r) => server.listen(0, "127.0.0.1", r));
  const base = `https://127.0.0.1:${server.address().port}`;
  try {
    await assert.rejects(fetch(`${base}/api/v1/user`), "plain fetch does not trust it");
    const trusting = fetchTrusting(cert);
    const me = await new HubClient(base, "tok", trusting).me();
    assert.equal(me.username, "andy");
    assert.equal(me.auth, "Bearer tok", "headers go through");
    const echo = await trusting(`${base}/echo`, { method: "POST", body: '{"a":1}', headers: { "content-type": "application/json" } });
    assert.equal(echo.status, 201);
    assert.deepEqual(await echo.json(), { method: "POST", body: '{"a":1}' });
    assert.equal((await trusting(`${base}/other`)).status, 204);
    await assert.rejects(fetchTrusting(join(dir, "missing.pem"))(`${base}/api/v1/user`), /cannot read the hub's CA file/);
  } finally {
    server.close();
  }
});
