/**
 * Error Sanitizer
 * 
 * Removes sensitive information from error messages before
 * displaying to users or logging to external systems.
 * 
 * Part of Sacred Pipeline Phase 3: Enhanced Error Handling
 */

import { logger } from './logger';

/**
 * Patterns that indicate sensitive data in error messages
 */
const SENSITIVE_PATTERNS = [
  // Authentication & Tokens
  /bearer\s+[a-zA-Z0-9\-_.]+/gi,
  /token[:\s]+[a-zA-Z0-9\-_.]+/gi,
  /api[_-]?key[:\s]+[a-zA-Z0-9\-_.]+/gi,
  /password[:\s]+[^\s]+/gi,
  /secret[:\s]+[a-zA-Z0-9\-_.]+/gi,
  
  // Database connection strings
  /postgresql:\/\/[^\s]+/gi,
  /postgres:\/\/[^\s]+/gi,
  /mysql:\/\/[^\s]+/gi,
  
  // IP addresses (internal)
  /\b(?:10|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\.\d{1,3}\.\d{1,3}\b/g,
  
  // Email addresses (in error messages)
  /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
  
  // UUIDs (can reveal internal IDs)
  /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,
  
  // File paths (Unix & Windows)
  /\/(?:home|root|usr|var|opt|mnt)\/[^\s]*/g,
  /[A-Z]:\\(?:Users|Windows|Program Files)[^\s]*/g,
  
  // Stack traces with file paths
  /at\s+[^\s]+\s+\([^\)]+\)/g,
  
  // SQL queries (can reveal schema)
  /SELECT\s+.+?\s+FROM\s+[^\s]+/gi,
  /INSERT\s+INTO\s+[^\s]+/gi,
  /UPDATE\s+[^\s]+\s+SET/gi,
  /DELETE\s+FROM\s+[^\s]+/gi,
];

/**
 * Common error message patterns to make more user-friendly
 */
const ERROR_MESSAGE_REPLACEMENTS: Array<[RegExp, string]> = [
  // Database errors
  [/duplicate key value violates unique constraint/gi, 'This item already exists'],
  [/foreign key constraint/gi, 'Related item not found'],
  [/violates check constraint/gi, 'Invalid data provided'],
  [/null value in column/gi, 'Required field is missing'],
  [/invalid input syntax for type/gi, 'Invalid data format'],
  
  // Auth errors
  [/JWT expired/gi, 'Session expired. Please log in again'],
  [/Invalid JWT/gi, 'Authentication failed. Please log in again'],
  [/No API key found/gi, 'Authentication required'],
  
  // Network errors
  [/ECONNREFUSED/gi, 'Service temporarily unavailable'],
  [/ETIMEDOUT/gi, 'Request timed out. Please try again'],
  [/ENOTFOUND/gi, 'Service not available'],
  [/Network request failed/gi, 'Network error. Check your connection'],
  
  // Rate limiting
  [/Too many requests/gi, 'Rate limit exceeded. Please wait before trying again'],
  
  // Supabase specific
  [/permission denied for table/gi, 'Access denied'],
  [/row level security policy/gi, 'Access denied'],
];

/**
 * Sanitize error message by removing sensitive information
 * 
 * @param error - Error object or message
 * @param context - Optional context for logging
 * @returns Sanitized error message safe for display
 */
export function sanitizeErrorMessage(
  error: unknown,
  context?: { action?: string; userId?: string }
): string {
  let message: string;

  // Extract message from error object
  if (error instanceof Error) {
    message = error.message;
  } else if (typeof error === 'string') {
    message = error;
  } else if (error && typeof error === 'object' && 'message' in error) {
    message = String((error as { message: unknown }).message);
  } else {
    message = 'An unexpected error occurred';
  }

  // Store original for logging
  const originalMessage = message;

  // Remove sensitive patterns
  SENSITIVE_PATTERNS.forEach(pattern => {
    message = message.replace(pattern, '[REDACTED]');
  });

  // Apply user-friendly replacements
  ERROR_MESSAGE_REPLACEMENTS.forEach(([pattern, replacement]) => {
    if (pattern.test(message)) {
      message = replacement;
    }
  });

  // If message was heavily sanitized, provide generic message
  if (message.includes('[REDACTED]')) {
    message = 'An error occurred. Please contact support if this persists';
  }

  // Log sanitization if message changed significantly
  if (originalMessage !== message && originalMessage.length > message.length + 10) {
    logger.info('[ErrorSanitizer] Sanitized error message', {
      action: context?.action,
      userId: context?.userId,
      originalLength: originalMessage.length,
      sanitizedLength: message.length,
      containsRedacted: message.includes('[REDACTED]'),
    });
  }

  return message;
}

/**
 * Check if error message contains sensitive data
 * 
 * @param message - Error message to check
 * @returns True if message contains sensitive patterns
 */
export function containsSensitiveData(message: string): boolean {
  return SENSITIVE_PATTERNS.some(pattern => pattern.test(message));
}

/**
 * Sanitize error object for logging to external systems
 * 
 * @param error - Error object to sanitize
 * @returns Sanitized error object
 */
export function sanitizeErrorForLogging(error: unknown): {
  message: string;
  name?: string;
  code?: string;
  stack?: string;
} {
  const sanitized: {
    message: string;
    name?: string;
    code?: string;
    stack?: string;
  } = {
    message: sanitizeErrorMessage(error),
  };

  if (error instanceof Error) {
    sanitized.name = error.name;

    // Sanitize stack trace
    if (error.stack) {
      let stack = error.stack;
      SENSITIVE_PATTERNS.forEach(pattern => {
        stack = stack.replace(pattern, '[REDACTED]');
      });
      sanitized.stack = stack;
    }

    // Include error code if present
    if ('code' in error && typeof error.code === 'string') {
      sanitized.code = error.code;
    }
  }

  return sanitized;
}

/**
 * Create a user-safe error response
 * 
 * @param error - Original error
 * @param fallbackMessage - Optional fallback message
 * @returns User-safe error object
 */
export function createSafeErrorResponse(
  error: unknown,
  fallbackMessage = 'An error occurred'
): {
  message: string;
  code?: string;
} {
  const sanitized = sanitizeErrorMessage(error);

  return {
    message: sanitized || fallbackMessage,
    code: error instanceof Error && 'code' in error 
      ? String((error as { code: string }).code)
      : undefined,
  };
}
