import assert from "node:assert/strict";
import { Readable } from "node:stream";
import test from "node:test";

import { readJson } from "./http.js";
import { resolveEntitlementRoute } from "./entitlement-routes.js";

const STATUS = {
  tier: "pro",
  state: "active",
  maxAccounts: 5,
  configuredAccounts: 2,
  expiresAt: "2026-09-01T12:00:00.000Z",
  graceEndsAt: "2026-09-08T12:00:00.000Z",
};

test("GET /entitlement returns only the safe public status fields", async () => {
  const result = await resolveEntitlementRoute(
    { method: "GET" },
    new URL("http://localhost/entitlement"),
    { store: { getStatus: async () => ({ ...STATUS, certificate: "secret", localPath: "private" }) } }
  );

  assert.deepEqual(result, { status: 200, body: STATUS });
});

test("POST challenge and activation responses project only allowlisted fields", async () => {
  const store = {
    issueChallenge: async () => ({
      challenge: "opaque-challenge",
      backendKeyThumbprint: "backend-thumbprint",
      privateKey: "secret",
    }),
    activate: async ({ challenge, certificate }) => {
      assert.equal(challenge, "opaque-challenge");
      assert.equal(certificate, "signed-certificate");
      return { ...STATUS, certificate, challenge };
    },
  };

  const challenge = await resolveEntitlementRoute(
    jsonRequest("POST", "{}"),
    new URL("http://localhost/entitlement/challenges"),
    { store, readJson }
  );
  const activation = await resolveEntitlementRoute(
    jsonRequest("POST", JSON.stringify({ challenge: "opaque-challenge", certificate: "signed-certificate" })),
    new URL("http://localhost/entitlement/activate"),
    { store, readJson }
  );

  assert.deepEqual(challenge, {
    status: 201,
    body: { challenge: "opaque-challenge", backendKeyThumbprint: "backend-thumbprint" },
  });
  assert.deepEqual(activation, { status: 200, body: STATUS });
});

test("entitlement mutations reject malformed, oversized, and unexpected input", async () => {
  const store = { issueChallenge: async () => ({}), activate: async () => ({}) };
  await assert.rejects(
    resolveEntitlementRoute(
      jsonRequest("POST", "{bad"),
      new URL("http://localhost/entitlement/challenges"),
      { store, readJson }
    ),
    error(400, "invalid_json")
  );
  await assert.rejects(
    resolveEntitlementRoute(
      jsonRequest("POST", JSON.stringify({ certificate: "x".repeat(20_000), challenge: "value" })),
      new URL("http://localhost/entitlement/activate"),
      { store, readJson }
    ),
    error(413, "request_too_large")
  );
  await assert.rejects(
    resolveEntitlementRoute(
      jsonRequest("POST", JSON.stringify({ challenge: "value", certificate: "token", extra: true })),
      new URL("http://localhost/entitlement/activate"),
      { store, readJson }
    ),
    error(400, "invalid_entitlement_request")
  );
  await assert.rejects(
    resolveEntitlementRoute(
      jsonRequest("POST", JSON.stringify({ unexpected: true })),
      new URL("http://localhost/entitlement/challenges"),
      { store, readJson }
    ),
    error(400, "invalid_entitlement_request")
  );
});

test("activation failures expose fixed safe codes without verifier details", async (t) => {
  const cases = [
    ["entitlement_challenge_expired", 409],
    ["entitlement_challenge_used", 409],
    ["invalid_entitlement_certificate", 400],
  ];
  for (const [code, status] of cases) {
    await t.test(code, async () => {
      const store = {
        activate: async () => {
          const failure = new Error(`private verifier detail C:\\secret\\${code}`);
          failure.code = code;
          failure.status = status;
          throw failure;
        },
      };
      await assert.rejects(
        resolveEntitlementRoute(
          jsonRequest("POST", JSON.stringify({ challenge: "value", certificate: "token" })),
          new URL("http://localhost/entitlement/activate"),
          { store, readJson }
        ),
        (failure) => {
          assert.equal(failure.status, status);
          assert.equal(failure.message, code);
          assert.equal(failure.safeLogCode, code);
          assert.equal(failure.message.includes("secret"), false);
          return true;
        }
      );
    });
  }
});

test("entitlement router ignores unrelated routes", async () => {
  assert.equal(await resolveEntitlementRoute(
    { method: "GET" },
    new URL("http://localhost/accounts"),
    { store: {} }
  ), null);
});

function jsonRequest(method, body) {
  return Object.assign(Readable.from([body]), { method });
}

function error(status, message) {
  return (value) => value?.status === status && value?.message === message;
}
