import assert from "node:assert/strict";
import test from "node:test";
import { assertAllowedOrigin, corsHeaders, prepareHttpRequest, publicErrorBody, sendEvent, sendJson } from "./http.js";

test("HTTP errors expose safe codes instead of raw secrets or paths", () => {
  const config = { workspaces: [{ path: "C:\\Project\\Codex-remote" }] };
  const error = new Error("Bearer secret-token at C:\\Project\\Codex-remote\\auth.json");
  error.status = 500;

  assert.deepEqual(publicErrorBody(error, config), { error: "internal_error" });
});

test("HTTP errors preserve explicit machine-readable public codes", () => {
  const error = new Error("invalid_session_context");
  error.status = 400;

  assert.deepEqual(publicErrorBody(error), { error: "invalid_session_context" });
});

test("HTTP errors prefer a safe explicit code over a human message", () => {
  const error = new Error("Pro is required to add another account.");
  error.status = 402;
  error.code = "pro_required";

  assert.deepEqual(publicErrorBody(error), { error: "pro_required" });
});

test("CORS allows only exact configured, local PWA, and native app origins", () => {
  const config = { allowedOrigins: ["https://codex.example.ts.net"] };

  assert.equal(corsHeaders("https://codex.example.ts.net", config)["access-control-allow-origin"], "https://codex.example.ts.net");
  assert.equal(corsHeaders("https://codex.example.ts.net", config)["access-control-allow-credentials"], "true");
  assert.equal(corsHeaders("http://127.0.0.1:43111", config)["access-control-allow-origin"], "http://127.0.0.1:43111");
  assert.equal(corsHeaders("https://localhost", config)["access-control-allow-origin"], "https://localhost");
  assert.equal("access-control-allow-origin" in corsHeaders("https://evil.example", config), false);
  assert.equal(corsHeaders(undefined, config)["access-control-allow-origin"], undefined);
});

test("CORS methods include every mutating HTTP route method", () => {
  assert.equal(corsHeaders()["access-control-allow-methods"], "GET,POST,PUT,PATCH,DELETE,OPTIONS");
});

test("rejects browser state changes from an untrusted origin", () => {
  const config = { allowedOrigins: ["https://codex.example.ts.net"] };

  assert.throws(
    () => assertAllowedOrigin({ method: "POST", headers: { origin: "https://evil.example" } }, config),
    (error) => error.message === "origin_not_allowed" && error.status === 403
  );
});

test("allows safe reads and requires Origin plus CSRF for browser state changes", () => {
  const config = { allowedOrigins: ["https://codex.example.ts.net"] };

  assert.doesNotThrow(() => assertAllowedOrigin({ method: "GET", headers: { origin: "https://evil.example" } }, config));
  assert.throws(() => assertAllowedOrigin({ method: "POST", headers: {} }, config), /origin_required/);
  assert.throws(
    () => assertAllowedOrigin({ method: "PATCH", headers: { origin: "https://codex.example.ts.net" } }, config),
    /csrf_required/
  );
  assert.doesNotThrow(() => assertAllowedOrigin({
    method: "PATCH",
    headers: { origin: "https://codex.example.ts.net", "x-code-remote-csrf": "1" }
  }, config));
});

test("HTTP request preparation applies CORS metadata before route authentication", () => {
  const config = { allowedOrigins: ["https://codex.example.ts.net"] };
  const response = {};

  assert.equal(
    prepareHttpRequest({ method: "POST", headers: { origin: "https://codex.example.ts.net" } }, response, config),
    "https://codex.example.ts.net"
  );
  assert.equal(response.corsHeaders["access-control-allow-origin"], "https://codex.example.ts.net");
  assert.doesNotThrow(() => prepareHttpRequest({ method: "DELETE", headers: { origin: "https://evil.example" } }, {}, config));
  assert.throws(() => assertAllowedOrigin({
    method: "DELETE",
    headers: { origin: "https://evil.example", "x-code-remote-csrf": "1" }
  }, config), /origin_not_allowed/);
});

test("HTTP and SSE apply one final safe projection", () => {
  const config = { workspaces: [{ path: "C:\\Project\\Codex-remote" }] };
  const chunks = [];
  const response = {
    writeHead() {},
    write(chunk) { chunks.push(String(chunk)); },
    end(chunk) { if (chunk) chunks.push(String(chunk)); }
  };
  prepareHttpRequest({ method: "GET", headers: {} }, response, config);

  sendJson(response, 200, {
    title: "Open C:\\Project\\Codex-remote\\auth.json",
    password: "plain password"
  });
  sendEvent(response, "snapshot", {
    authorization: "Basic dXNlcjpwYXNz",
    safe: "apps/backend/src/index.js"
  });

  const output = chunks.join("\n");
  assert.equal(output.includes("plain password"), false);
  assert.equal(output.includes("dXNlcjpwYXNz"), false);
  assert.equal(output.includes("C:\\Project\\Codex-remote"), false);
  assert.match(output, /apps\/backend\/src\/index\.js/);
});
