import nodeCrypto from "crypto";

const MAX_REQUEST_ID_LENGTH = 256;
const REQUEST_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;

/**
 * Validates a request ID for safe logging: enforces max length
 * and whitelist of safe characters to prevent log injection.
 */
function isValidRequestId(id: string): boolean {
  if (id.length > MAX_REQUEST_ID_LENGTH) return false;
  if (!REQUEST_ID_PATTERN.test(id)) return false;
  return true;
}

/**
 * Generates a unique request ID for distributed tracing.
 * Uses crypto.randomUUID when available, falls back to a
 * Node.js crypto.randomBytes-based UUID v4 format.
 */
export function generateRequestId(): string {
  if (typeof crypto !== "undefined" && crypto.randomUUID) {
    return crypto.randomUUID();
  }
  const bytes = nodeCrypto.randomBytes(16);
  bytes[6] = (bytes[6] & 0x0f) | 0x40;
  bytes[8] = (bytes[8] & 0x3f) | 0x80;
  const hex = bytes.toString("hex");
  return (
    hex.slice(0, 8) + "-" +
    hex.slice(8, 12) + "-" +
    hex.slice(12, 16) + "-" +
    hex.slice(16, 20) + "-" +
    hex.slice(20, 32)
  );
}

/**
 * Extracts an existing request ID from headers or generates a new one.
 * Checks standard headers: X-Request-Id, X-Correlation-Id, X-Trace-Id.
 * Validates extracted IDs for safe logging (max 256 chars, alphanumeric/hyphen/underscore).
 */
export function extractOrGenerateRequestId(headers: Record<string, string | string[] | undefined>): string {
  const candidates = ["x-request-id", "x-correlation-id", "x-trace-id"];
  for (const key of candidates) {
    const value = headers[key];
    if (typeof value === "string") {
      const trimmed = value.trim();
      if (trimmed && isValidRequestId(trimmed)) {
        return trimmed;
      }
    }
    if (Array.isArray(value) && value[0]) {
      const trimmed = value[0].trim();
      if (isValidRequestId(trimmed)) {
        return trimmed;
      }
    }
  }
  return generateRequestId();
}
