import assert from "node:assert/strict";
import { generateKeyPairSync, sign } from "node:crypto";
import test from "node:test";

import { verifyEntitlementToken } from "./entitlement-token.js";

const DAY_SECONDS = 24 * 60 * 60;
const NOW = Date.UTC(2026, 7, 2, 12, 0, 0);
const NOW_SECONDS = Math.floor(NOW / 1000);

function encode(value) {
  return Buffer.from(JSON.stringify(value)).toString("base64url");
}

function fixture(overrides = {}) {
  const { publicKey, privateKey } = generateKeyPairSync("ed25519");
  const header = { alg: "EdDSA", kid: "release-2026-01" };
  const claims = {
    iss: "crm-entitlement-verifier",
    aud: "code-remote-manager-backend",
    productId: "pro_multi_account",
    maxAccounts: 5,
    backendKeyThumbprint: "backend-thumbprint",
    challengeHash: "challenge-hash",
    iat: NOW_SECONDS,
    exp: NOW_SECONDS + (30 * DAY_SECONDS),
    jti: "certificate-id",
  };
  Object.assign(header, overrides.header);
  Object.assign(claims, overrides.claims);
  const signingInput = `${encode(header)}.${encode(claims)}`;
  const signature = sign(null, Buffer.from(signingInput), privateKey).toString("base64url");
  return {
    claims,
    publicKey,
    token: `${signingInput}.${signature}`,
  };
}

function verify(tokenFixture, overrides = {}) {
  return verifyEntitlementToken(tokenFixture.token, {
    publicKeys: { "release-2026-01": tokenFixture.publicKey },
    backendKeyThumbprint: "backend-thumbprint",
    challengeHash: "challenge-hash",
    now: NOW,
    ...overrides,
  });
}

test("verifies a bound Ed25519 Pro entitlement certificate", () => {
  const tokenFixture = fixture();

  assert.deepEqual(verify(tokenFixture), tokenFixture.claims);
});

test("rejects certificates that cannot establish the required trust boundary", async (t) => {
  const cases = [
    ["unknown key id", { header: { kid: "unknown" } }],
    ["wrong audience", { claims: { aud: "another-service" } }],
    ["wrong product", { claims: { productId: "another_product" } }],
    ["wrong account limit", { claims: { maxAccounts: 6 } }],
    ["wrong backend binding", { claims: { backendKeyThumbprint: "another-backend" } }],
    ["wrong challenge binding", { claims: { challengeHash: "another-challenge" } }],
    ["future issue time", { claims: { iat: NOW_SECONDS + 1 } }],
    ["expired certificate", { claims: { exp: NOW_SECONDS } }],
  ];

  for (const [name, overrides] of cases) {
    await t.test(name, () => {
      const tokenFixture = fixture(overrides);
      assert.throws(
        () => verify(tokenFixture),
        (error) => error?.code === "invalid_entitlement_certificate"
      );
    });
  }
});

test("rejects a certificate signed by a different key", () => {
  const tokenFixture = fixture();
  const otherKey = generateKeyPairSync("ed25519").publicKey;

  assert.throws(
    () => verify(tokenFixture, { publicKeys: { "release-2026-01": otherKey } }),
    (error) => error?.code === "invalid_entitlement_certificate"
  );
});
