import { verify } from "node:crypto";

const AUDIENCE = "code-remote-manager-backend";
const PRODUCT_ID = "pro_multi_account";
const MAX_ACCOUNTS = 5;
const HEADER_FIELDS = ["alg", "kid"];
const CLAIM_FIELDS = [
  "aud",
  "backendKeyThumbprint",
  "challengeHash",
  "exp",
  "iat",
  "iss",
  "jti",
  "maxAccounts",
  "productId",
];

function invalidCertificate() {
  const error = new Error("The entitlement certificate is invalid.");
  error.status = 400;
  error.code = "invalid_entitlement_certificate";
  return error;
}

function isExactObject(value, fields) {
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
  const keys = Object.keys(value).sort();
  return keys.length === fields.length && fields.every((field, index) => keys[index] === field);
}

function decodeJson(segment) {
  if (!/^[A-Za-z0-9_-]+$/.test(segment)) throw invalidCertificate();
  const decoded = Buffer.from(segment, "base64url");
  if (decoded.toString("base64url") !== segment) throw invalidCertificate();
  try {
    return JSON.parse(decoded.toString("utf8"));
  } catch {
    throw invalidCertificate();
  }
}

function publicKeyFor(publicKeys, keyId) {
  if (publicKeys instanceof Map) return publicKeys.get(keyId);
  if (!publicKeys || typeof publicKeys !== "object" || !Object.hasOwn(publicKeys, keyId)) return null;
  return publicKeys[keyId];
}

export function verifyEntitlementToken(token, {
  publicKeys,
  backendKeyThumbprint,
  challengeHash,
  now = Date.now(),
}) {
  try {
    if (typeof token !== "string") throw invalidCertificate();
    const segments = token.split(".");
    if (segments.length !== 3 || segments.some((segment) => !segment)) throw invalidCertificate();

    const [encodedHeader, encodedClaims, encodedSignature] = segments;
    const header = decodeJson(encodedHeader);
    if (!isExactObject(header, HEADER_FIELDS) || header.alg !== "EdDSA" || typeof header.kid !== "string") {
      throw invalidCertificate();
    }

    const publicKey = publicKeyFor(publicKeys, header.kid);
    if (!publicKey || !/^[A-Za-z0-9_-]+$/.test(encodedSignature)) throw invalidCertificate();
    const signature = Buffer.from(encodedSignature, "base64url");
    if (signature.toString("base64url") !== encodedSignature) throw invalidCertificate();
    const signingInput = `${encodedHeader}.${encodedClaims}`;
    if (!verify(null, Buffer.from(signingInput), publicKey, signature)) throw invalidCertificate();

    const claims = decodeJson(encodedClaims);
    const nowSeconds = Math.floor(now / 1000);
    if (
      !isExactObject(claims, CLAIM_FIELDS)
      || typeof claims.iss !== "string"
      || claims.iss.length === 0
      || claims.aud !== AUDIENCE
      || claims.productId !== PRODUCT_ID
      || claims.maxAccounts !== MAX_ACCOUNTS
      || claims.backendKeyThumbprint !== backendKeyThumbprint
      || claims.challengeHash !== challengeHash
      || !Number.isSafeInteger(claims.iat)
      || !Number.isSafeInteger(claims.exp)
      || claims.iat > nowSeconds
      || claims.exp <= nowSeconds
      || claims.exp <= claims.iat
      || typeof claims.jti !== "string"
      || claims.jti.length === 0
    ) {
      throw invalidCertificate();
    }

    return { ...claims };
  } catch (error) {
    if (error?.code === "invalid_entitlement_certificate") throw error;
    throw invalidCertificate();
  }
}
