// Minimal ULID implementation (Crockford Base32) for msgId/correlationId.
// No external dependencies.

const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';

function encodeTime(timeMs: number): string {
  // 48-bit timestamp -> 10 chars base32
  let time = BigInt(timeMs);
  const chars: string[] = new Array(10);
  for (let i = 9; i >= 0; i--) {
    const mod = Number(time % 32n);
    chars[i] = ENCODING[mod];
    time = time / 32n;
  }
  return chars.join('');
}

function encodeRandom(bytes: Uint8Array): string {
  // 80 bits (10 bytes) -> 16 chars base32
  // We treat as big-endian.
  let v = 0n;
  for (const b of bytes) {
    v = (v << 8n) | BigInt(b);
  }
  const chars: string[] = new Array(16);
  for (let i = 15; i >= 0; i--) {
    const mod = Number(v % 32n);
    chars[i] = ENCODING[mod];
    v = v / 32n;
  }
  return chars.join('');
}

export function ulid(nowMs: number = Date.now()): string {
  // WebCrypto is available in Node 18+ as globalThis.crypto.
  const rnd = new Uint8Array(10);
  globalThis.crypto.getRandomValues(rnd);
  return encodeTime(nowMs) + encodeRandom(rnd);
}
