import test from "node:test";
import assert from "node:assert/strict";
import { verifyServerConnection } from "./connection.js";
import { disconnectPcConnection } from "./connection-mode.js";
import { scanConnectionSetupQr, scanDevicePairingQr, scanPcConnectionQr } from "./qr-scanner.js";

test("connection verification checks the safe health endpoint", async () => {
  const calls = [];
  const fetchImpl = async (...args) => {
    calls.push(args);
    return { ok: true };
  };

  await verifyServerConnection("codex.example.ts.net", fetchImpl);

  assert.deepEqual(calls, [["https://codex.example.ts.net/api/health", { cache: "no-store", credentials: "include" }]]);
});

test("disconnect removes both the saved PC and pending change state", () => {
  const localValues = new Map([["codexRemote.serverOrigin", "https://pc.example.ts.net"]]);
  const sessionValues = new Map([["codexRemote.changePc", "1"]]);
  const localStorage = { removeItem: (key) => localValues.delete(key) };
  const sessionStorage = { removeItem: (key) => sessionValues.delete(key) };

  disconnectPcConnection({ localStorage, sessionStorage });

  assert.equal(localValues.size, 0);
  assert.equal(sessionValues.size, 0);
});

test("connection verification reports unreachable PCs without leaking errors", async () => {
  await assert.rejects(
    verifyServerConnection("codex.example.ts.net", async () => { throw new Error("private network detail"); }),
    /pc_unreachable/
  );
  await assert.rejects(
    verifyServerConnection("codex.example.ts.net", async () => ({ ok: false })),
    /pc_unreachable/
  );
});

test("QR scanning requests only a QR code and returns its PC address", async () => {
  let options;
  const scanner = { scanBarcode: async (value) => { options = value; return { ScanResult: "https://pc.example.ts.net", format: 0 }; } };

  const address = await scanPcConnectionQr(scanner, { instructions: "Scan", cancel: "Cancel" });

  assert.equal(address, "https://pc.example.ts.net");
  assert.equal(options.hint, 0);
  assert.equal(options.scanButton, false);
  assert.equal(options.cancelButtonAccessibilityLabel, "Cancel");
});

test("QR scanning rejects an empty scan result", async () => {
  const scanner = { scanBarcode: async () => ({ ScanResult: "" }) };
  await assert.rejects(() => scanPcConnectionQr(scanner), /invalid_qr_code/);
});

test("pairing QR scanning returns only a validated pairing payload", async () => {
  const payload = "crm-pair:v1:eyJvcmlnaW4iOiJodHRwczovL3BjLmV4YW1wbGUudHMubmV0IiwiYXR0ZW1wdElkIjoiYXR0ZW1wdC0xMjM0NTY3OCIsInNlY3JldCI6Il9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXyIsImV4cGlyZXNBdCI6IjIwOTktMDEtMDFUMDA6MDA6MDAuMDAwWiJ9";
  const scanner = { scanBarcode: async () => ({ ScanResult: payload }) };

  const result = await scanDevicePairingQr(scanner);

  assert.equal(result.origin, "https://pc.example.ts.net");
  assert.equal(result.attemptId, "attempt-12345678");
});

test("first connection can use one pairing QR for both the PC address and authentication", async () => {
  const payload = "crm-pair:v1:eyJvcmlnaW4iOiJodHRwczovL3BjLmV4YW1wbGUudHMubmV0IiwiYXR0ZW1wdElkIjoiYXR0ZW1wdC0xMjM0NTY3OCIsInNlY3JldCI6Il9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXyIsImV4cGlyZXNBdCI6IjIwOTktMDEtMDFUMDA6MDA6MDAuMDAwWiJ9";
  const scanner = { scanBarcode: async () => ({ ScanResult: payload }) };

  const result = await scanConnectionSetupQr(scanner);

  assert.equal(result.origin, "https://pc.example.ts.net");
  assert.equal(result.pairing.attemptId, "attempt-12345678");
});
