import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';

export const TOKEN_PREFIX = 'mcpctl_pat_';

// base62 alphabet (URL/header safe, no ambiguous chars across all positions)
const BASE62 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

export interface GeneratedToken {
  /** The raw token — `mcpctl_pat_<32 base62 chars>`. Shown once at create time; never stored. */
  raw: string;
  /** SHA-256 hex digest of the raw value. Persist this, not the raw value. */
  hash: string;
  /** First 16 chars of the raw token, safe to display (e.g. in `mcpctl get mcptoken`). */
  prefix: string;
}

export function generateToken(): GeneratedToken {
  const bytes = randomBytes(24);
  let body = '';
  for (const b of bytes) body += BASE62[b % 62];
  const raw = TOKEN_PREFIX + body;
  return { raw, hash: hashToken(raw), prefix: raw.slice(0, 16) };
}

export function hashToken(raw: string): string {
  return createHash('sha256').update(raw).digest('hex');
}

export function isMcpToken(bearer: string): boolean {
  return bearer.startsWith(TOKEN_PREFIX);
}

/** Constant-time compare two equal-length hex strings. Returns false on length mismatch. */
export function timingSafeEqualHex(a: string, b: string): boolean {
  if (a.length !== b.length) return false;
  try {
    return timingSafeEqual(Buffer.from(a, 'hex'), Buffer.from(b, 'hex'));
  } catch {
    return false;
  }
}
