import assert from "node:assert/strict";
import test from "node:test";

import {
  assertCanAddExecutionAccount,
  getAccountExecutionAccess,
  getPublicEntitlementStatus,
} from "./entitlement-policy.js";

const DAY_MS = 24 * 60 * 60 * 1000;
const NOW = Date.UTC(2026, 7, 2, 12, 0, 0);

function certificate({ expiresAt = NOW + (30 * DAY_MS) } = {}) {
  return {
    productId: "pro_multi_account",
    maxAccounts: 5,
    iat: Math.floor(NOW / 1000),
    exp: Math.floor(expiresAt / 1000),
  };
}

function accounts(count, { historyOnly = 0 } = {}) {
  return [
    ...Array.from({ length: count }, (_, index) => ({ id: `account-${index + 1}` })),
    ...Array.from({ length: historyOnly }, (_, index) => ({
      id: `history-${index + 1}`,
      historyOnly: true,
    })),
  ];
}

test("free status allows only the first execution account and ignores history sources", () => {
  const configured = accounts(2, { historyOnly: 2 });
  const status = getPublicEntitlementStatus({ certificate: null, accounts: configured, now: NOW });

  assert.deepEqual(status, {
    tier: "free",
    state: "active",
    maxAccounts: 1,
    configuredAccounts: 2,
    expiresAt: null,
    graceEndsAt: null,
  });
  assert.deepEqual(getAccountExecutionAccess({
    accountId: "account-1",
    accounts: configured,
    entitlement: status,
  }), { allowed: true, entitlementLocked: false });
  assert.deepEqual(getAccountExecutionAccess({
    accountId: "account-2",
    accounts: configured,
    entitlement: status,
  }), {
    allowed: false,
    entitlementLocked: true,
    status: 402,
    code: "pro_required",
    message: "Pro is required to use this account.",
  });
});

test("Pro status allows five execution accounts in deterministic config order", () => {
  const configured = accounts(6, { historyOnly: 1 });
  const status = getPublicEntitlementStatus({
    certificate: certificate(),
    accounts: configured,
    now: NOW,
  });

  assert.equal(status.tier, "pro");
  assert.equal(status.state, "active");
  assert.equal(status.maxAccounts, 5);
  assert.equal(status.configuredAccounts, 6);
  for (const account of configured.slice(0, 5)) {
    assert.equal(getAccountExecutionAccess({
      accountId: account.id,
      accounts: configured,
      entitlement: status,
    }).allowed, true);
  }
  assert.equal(getAccountExecutionAccess({
    accountId: "account-6",
    accounts: configured,
    entitlement: status,
  }).allowed, false);
});

test("Pro remains active for 30 days, enters seven-day grace, then expires", () => {
  const expiresAt = NOW + (30 * DAY_MS);
  const configured = accounts(2);

  const active = getPublicEntitlementStatus({
    certificate: certificate({ expiresAt }),
    accounts: configured,
    now: expiresAt - 1,
  });
  const grace = getPublicEntitlementStatus({
    certificate: certificate({ expiresAt }),
    accounts: configured,
    now: expiresAt,
  });
  const expired = getPublicEntitlementStatus({
    certificate: certificate({ expiresAt }),
    accounts: configured,
    now: expiresAt + (7 * DAY_MS),
  });

  assert.equal(active.state, "active");
  assert.equal(active.maxAccounts, 5);
  assert.equal(grace.state, "grace");
  assert.equal(grace.maxAccounts, 5);
  assert.equal(expired.tier, "free");
  assert.equal(expired.state, "expired");
  assert.equal(expired.maxAccounts, 1);
});

test("capacity errors expose only a safe status, code, and message", () => {
  const free = getPublicEntitlementStatus({ certificate: null, accounts: accounts(1), now: NOW });
  assert.throws(
    () => assertCanAddExecutionAccount({ accounts: accounts(1), entitlement: free }),
    (error) => {
      assert.equal(error.status, 402);
      assert.equal(error.code, "pro_required");
      assert.equal(error.message, "Pro is required to add another account.");
      return true;
    }
  );

  const pro = getPublicEntitlementStatus({ certificate: certificate(), accounts: accounts(5), now: NOW });
  assert.throws(
    () => assertCanAddExecutionAccount({ accounts: accounts(5), entitlement: pro }),
    (error) => {
      assert.equal(error.status, 409);
      assert.equal(error.code, "account_limit_reached");
      assert.equal(error.message, "The account limit has been reached.");
      return true;
    }
  );
});
