/**
 * Sanitizes user input to prevent prompt injection attacks
 * Strips control characters, limits length, and escapes template injection
 */

/**
 * Strip control characters (0x00-0x1F, 0x7F)
 * 
 * @param str - Input string to clean
 * @returns String with control characters removed
 * 
 * @example
 * stripControlChars('Hello\x00World\x1F')
 * // Returns: 'HelloWorld'
 */
function stripControlChars(str: string): string {
  return str.replace(/[\x00-\x1F\x7F]/g, '');
}

/**
 * Escape template literals to prevent injection
 * Prevents template literal injection by escaping backticks, $, and backslashes
 * 
 * @param str - Input string to escape
 * @returns Escaped string safe for template literals
 * 
 * @example
 * escapeTemplateLiterals('Hello ${user.name}')
 * // Returns: 'Hello \${user.name}'
 * 
 * @example
 * escapeTemplateLiterals('Backtick: `code`')
 * // Returns: 'Backtick: \`code\`'
 */
function escapeTemplateLiterals(str: string): string {
  return str
    .replace(/\\/g, '\\\\')  // Escape backslashes first
    .replace(/\$/g, '\\$')   // Escape $ to prevent ${} injection
    .replace(/`/g, '\\`');   // Escape backticks
}

/**
 * Sanitize string input to prevent security issues and normalize data
 * Strips control characters, escapes template literals, trims whitespace, and enforces length limits
 * 
 * @param input - String input to sanitize
 * @param options - Sanitization options
 * @param options.maxLength - Maximum allowed length (truncates if longer)
 * @param options.stripControls - Whether to strip control characters (default: true)
 * @param options.escapeTemplates - Whether to escape template literals (default: true)
 * @returns Sanitized string
 * 
 * @example
 * sanitizeInput('Hello\x00World')
 * // Returns: 'HelloWorld'
 * 
 * @example
 * sanitizeInput('  Hello ${injection}  ', { maxLength: 10 })
 * // Returns: 'Hello \${injection}'
 * 
 * @example
 * sanitizeInput('user input', { stripControls: false, escapeTemplates: false })
 * // Returns: 'user input'
 */
export function sanitizeInput(
  input: string,
  options: {
    maxLength?: number;
    stripControls?: boolean;
    escapeTemplates?: boolean;
  } = {}
): string {
  if (typeof input !== 'string') {
    return '';
  }

  let sanitized = input;

  // Strip control characters by default
  if (options.stripControls !== false) {
    sanitized = stripControlChars(sanitized);
  }

  // Trim whitespace
  sanitized = sanitized.trim();

  // Limit length BEFORE escaping to avoid cutting in the middle of escape sequences
  if (options.maxLength && sanitized.length > options.maxLength) {
    sanitized = sanitized.substring(0, options.maxLength);
  }

  // Escape template literals by default (after truncation)
  if (options.escapeTemplates !== false) {
    sanitized = escapeTemplateLiterals(sanitized);
  }

  return sanitized;
}

/**
 * Strip phone numbers and email addresses from text to prevent
 * contractors and workers from bypassing the platform.
 *
 * Handles Australian phone formats: 04xx xxx xxx, +614xxxxxxxx, (02) xxxx xxxx, etc.
 * Handles email addresses: user@domain.com
 *
 * @param input - String to strip contact info from
 * @returns String with phone numbers and emails replaced with [removed]
 */
export function stripContactInfo(input: string): string {
  if (typeof input !== 'string') return '';

  let result = input;

  // Australian mobile: 04xx xxx xxx, 04xxxxxxxx, +614xxxxxxxx
  result = result.replace(/(\+?61\s?|0)4\d{2}[\s.-]?\d{3}[\s.-]?\d{3}/g, '[removed]');

  // Australian landline: (0x) xxxx xxxx, 0x xxxx xxxx
  result = result.replace(/\(?0[2-9]\)?[\s.-]?\d{4}[\s.-]?\d{4}/g, '[removed]');

  // General international numbers: +xx xxxxxxxxxx (10+ digits with optional separators)
  result = result.replace(/\+\d{1,3}[\s.-]?\d[\d\s.-]{8,}/g, '[removed]');

  // Catch remaining digit sequences that look like phone numbers (8-12 digits with separators)
  result = result.replace(/\b\d{4}[\s.-]\d{3}[\s.-]\d{3}\b/g, '[removed]');

  // Email addresses
  result = result.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, '[removed]');

  // Clean up multiple consecutive [removed] markers
  result = result.replace(/(\[removed\]\s*){2,}/g, '[removed] ');

  return result;
}

/**
 * Sanitize multiple string inputs at once with field-specific options
 * Useful for form data where different fields have different validation rules
 * 
 * @param inputs - Object with string values to sanitize
 * @param fieldOptions - Per-field sanitization options (keyed by field name)
 * @returns Object with sanitized values
 * 
 * @example
 * sanitizeInputs(
 *   { name: 'John Doe', bio: 'Hello\x00World', email: '  john@example.com  ' },
 *   { bio: { maxLength: 500 }, email: { maxLength: 100 } }
 * )
 * // Returns: { name: 'John Doe', bio: 'HelloWorld', email: 'john@example.com' }
 */
export function sanitizeInputs(
  inputs: Record<string, string>,
  fieldOptions: Record<string, { maxLength?: number }> = {}
): Record<string, string> {
  const sanitized: Record<string, string> = {};

  for (const [key, value] of Object.entries(inputs)) {
    const options = fieldOptions[key] || {};
    sanitized[key] = sanitizeInput(value, options);
  }

  return sanitized;
}