"use strict";

const test = require("node:test");
const assert = require("node:assert/strict");
const crypto = require("node:crypto");
const {
  GuanghuRouter,
  canonicalApproval,
  canonicalConnect,
  workorderDigest,
} = require("./guanghu-router");

function registeredDevice() {
  const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");
  const publicJwk = publicKey.export({ format: "jwk" });
  return {
    device: {
      device_id: "HL-BS-MAC-001",
      owner_id: "owner",
      label: "冰朔的 HoloLake",
      public_key: publicJwk.x,
      enabled: true,
    },
    privateKey,
  };
}

function signedConnect(router, device, privateKey, now) {
  const challenge = router.challenge(device.device_id, now);
  assert.equal(challenge.ok, true);
  const signature = crypto.sign(
    null,
    Buffer.from(canonicalConnect({
      deviceId: device.device_id,
      challengeId: challenge.challengeId,
      nonce: challenge.nonce,
      clientTimestamp: now,
    })),
    privateKey,
  ).toString("base64url");
  return router.authorizeConnection({
    deviceId: device.device_id,
    challengeId: challenge.challengeId,
    clientTimestamp: now,
    signature,
  }, now);
}

test("only a registered device with a valid signature receives a one-time route token", () => {
  const { device, privateKey } = registeredDevice();
  const router = new GuanghuRouter({ devices: [device] });
  assert.deepEqual(router.challenge("unknown-device", 1_000), {
    ok: false,
    reason: "device_not_registered",
  });

  const challenge = router.challenge(device.device_id, 1_000);
  const rejected = router.authorizeConnection({
    deviceId: device.device_id,
    challengeId: challenge.challengeId,
    clientTimestamp: 1_000,
    signature: "invalid",
  }, 1_000);
  assert.equal(rejected.ok, false);
  assert.equal(rejected.reason, "device_signature_invalid");

  const authorized = signedConnect(router, device, privateKey, 1_001);
  assert.equal(authorized.ok, true);
  assert.match(authorized.routeToken, /^[A-Za-z0-9_-]{40,}$/);
  assert.equal(router.isApproverOnline("owner"), false);
});

test("the open transport is the online fact and closing it makes the device offline", () => {
  const { device, privateKey } = registeredDevice();
  const router = new GuanghuRouter({ devices: [device] });
  const authorized = signedConnect(router, device, privateKey, 2_000);
  const events = [];
  const opened = router.open(authorized.routeToken, event => events.push(event), 2_001);

  assert.equal(opened.ok, true);
  assert.equal(opened.state, "online");
  assert.equal(router.isApproverOnline("owner"), true);
  assert.equal(events[0].type, "router.connected");
  assert.equal(events[0].receipt.state, "online");
  assert.equal(router.open(authorized.routeToken, () => {}, 2_002).reason, "route_token_not_found");

  opened.close(2_003);
  assert.equal(router.isApproverOnline("owner"), false);
  assert.equal(events.at(-1).type, "router.closed");
  assert.equal(events.at(-1).receipt.state, "offline");
});

test("authorization cards travel through the already-open route", () => {
  const { device, privateKey } = registeredDevice();
  const router = new GuanghuRouter({ devices: [device] });
  const authorized = signedConnect(router, device, privateKey, 3_000);
  const events = [];
  router.open(authorized.routeToken, event => events.push(event), 3_001);
  const order = {
    id: "203e12af-f821-4b62-b80f-b3d73df05161",
    persona: { pid: "ICE-GL-ZY001", name: "铸渊" },
    target: "JD-FD-PRIMARY",
    scope: "server-login",
    action: "read-navigation-map",
    allowed_actions: ["read-navigation-map", "inspect-services"],
    description: "进入第五域",
    resource: "",
    createdAt: 3_000,
    expiresAt: 4_000,
    state: "pending",
  };
  assert.equal(router.deliver("owner", order), 1);
  const card = events.at(-1);
  assert.equal(card.type, "authorization.requested");
  assert.equal(card.workorder.id, order.id);
  assert.equal(card.digest, workorderDigest(order));
});

test("the bound device signs the exact authorization card digest", () => {
  const { device, privateKey } = registeredDevice();
  const router = new GuanghuRouter({ devices: [device] });
  const authorized = signedConnect(router, device, privateKey, 4_000);
  router.open(authorized.routeToken, () => {}, 4_001);
  const order = {
    id: "203e12af-f821-4b62-b80f-b3d73df05161",
    persona: { pid: "ICE-GL-ZY001", name: "铸渊" },
    target: "JD-FD-PRIMARY",
    scope: "server-login",
    action: "read-navigation-map",
    allowed_actions: ["read-navigation-map", "inspect-services"],
    description: "进入第五域",
    resource: "",
    createdAt: 4_000,
    expiresAt: 5_000,
    state: "pending",
  };
  const digest = workorderDigest(order);
  const signature = crypto.sign(
    null,
    Buffer.from(canonicalApproval({
      deviceId: device.device_id,
      workorderId: order.id,
      digest,
    })),
    privateKey,
  ).toString("base64url");

  const verified = router.verifyApproval(
    device.device_id,
    order,
    signature,
  );
  assert.equal(verified.ok, true);
  assert.equal(verified.authorizerId, "owner");
  assert.equal(verified.deviceId, device.device_id);

  const changed = { ...order, action: "inspect-services" };
  assert.equal(
    router.verifyApproval(device.device_id, changed, signature).reason,
    "device_signature_invalid",
  );
});
