"use strict";

const assert = require("node:assert/strict");
const test = require("node:test");
const http = require("node:http");
const { createApp } = require("../server");
const fs = require("node:fs");
const path = require("node:path");

test("JD hub exposes a minimal non-secret status response", async (t) => {
  const server = createApp().listen(0, "127.0.0.1");
  t.after(() => server.close());
  await new Promise((resolve) => server.once("listening", resolve));
  const { port } = server.address();
  const response = await fetch(`http://127.0.0.1:${port}/api/status`);
  assert.equal(response.status, 200);
  const body = await response.json();
  assert.equal(body.ok, true);
  assert.equal(body.node_id, "JD-FD-PRIMARY");
  assert.equal("ip" in body, false);
  assert.equal("token" in body, false);
});

test("JD hub serves its application page", async (t) => {
  const server = createApp().listen(0, "127.0.0.1");
  t.after(() => server.close());
  await new Promise((resolve) => server.once("listening", resolve));
  const { port } = server.address();
  const response = await fetch(`http://127.0.0.1:${port}/`);
  assert.equal(response.status, 200);
  assert.match(await response.text(), /京东云主节点/);
});

test("JD hub strips its public route before proxying to the code channel", async (t) => {
  const upstream = http.createServer((request, response) => {
    response.writeHead(200, { "content-type": "application/json" });
    response.end(JSON.stringify({
      path: request.url,
      method: request.method,
      host: request.headers.host,
      proto: request.headers["x-forwarded-proto"]
    }));
  });
  upstream.listen(0, "127.0.0.1");
  t.after(() => upstream.close());
  await new Promise((resolve) => upstream.once("listening", resolve));

  const server = createApp({ codeChannelPort: upstream.address().port }).listen(0, "127.0.0.1");
  t.after(() => server.close());
  await new Promise((resolve) => server.once("listening", resolve));
  const response = await new Promise((resolve, reject) => {
    const request = http.get({
      host: "127.0.0.1",
      port: server.address().port,
      path: "/code/api/v1/version",
      headers: { host: "guanghulab.com", "x-forwarded-proto": "https" }
    }, resolve);
    request.on("error", reject);
  });
  const chunks = [];
  for await (const chunk of response) chunks.push(chunk);
  assert.equal(response.statusCode, 200);
  assert.deepEqual(JSON.parse(Buffer.concat(chunks).toString("utf8")), {
    path: "/api/v1/version",
    method: "GET",
    host: "guanghulab.com",
    proto: "https"
  });
});

test("JD hub preserves nested code-channel paths and queries without duplicating the public prefix", async (t) => {
  const upstream = http.createServer((request, response) => {
    response.writeHead(200, { "content-type": "application/json" });
    response.end(JSON.stringify({ path: request.url }));
  });
  upstream.listen(0, "127.0.0.1");
  t.after(() => upstream.close());
  await new Promise((resolve) => upstream.once("listening", resolve));

  const server = createApp({ codeChannelPort: upstream.address().port }).listen(0, "127.0.0.1");
  t.after(() => server.close());
  await new Promise((resolve) => server.once("listening", resolve));

  const nested = await fetch(`http://127.0.0.1:${server.address().port}/code/user/login?redirect_to=%2Fjd%2Fcode%2F`);
  assert.equal(nested.status, 200);
  assert.deepEqual(await nested.json(), {
    path: "/user/login?redirect_to=%2Fjd%2Fcode%2F"
  });

  const root = await fetch(`http://127.0.0.1:${server.address().port}/code/`);
  assert.equal(root.status, 200);
  assert.deepEqual(await root.json(), { path: "/" });
});

test("JD hub exposes only a categorized candidate failure", async (t) => {
  const upstream = http.createServer((_request, response) => {
    response.writeHead(200, { "content-type": "application/json" });
    response.end(JSON.stringify({
      ok: false,
      version: "16.0.1",
      code: "HLCC-JD-CANDIDATE-01",
      ready: false,
      stage: "failed",
      error: "[Errno 2] No such file or directory: gpg /private/server/path"
    }));
  });
  upstream.listen(0, "127.0.0.1");
  t.after(() => upstream.close());
  await new Promise((resolve) => upstream.once("listening", resolve));

  const server = createApp({ codeChannelHealthPort: upstream.address().port }).listen(0, "127.0.0.1");
  t.after(() => server.close());
  await new Promise((resolve) => server.once("listening", resolve));
  const response = await fetch(`http://127.0.0.1:${server.address().port}/api/code-channel-status`);
  assert.equal(response.status, 200);
  assert.deepEqual(await response.json(), {
    ok: false,
    version: "16.0.1",
    code: "HLCC-JD-CANDIDATE-01",
    ready: false,
    stage: "failed",
    failure_category: "signature_verifier_unavailable"
  });
});

test("tunnel service keeps private addresses outside the repository", () => {
  const unit = fs.readFileSync(path.join(__dirname, "..", "guanghu-jd-web-tunnel.service"), "utf8");
  assert.match(unit, /\/etc\/guanghu\/jd-web-tunnel-ssh-config/);
  assert.doesNotMatch(unit, /(?:\d{1,3}\.){3}\d{1,3}/);
});
