/**
 * Logger utility for frontend application
 * Replaces console statements with proper logging that can be controlled in production
 * Sanitizes sensitive data from logs to prevent information disclosure
 */

type LogLevel = 'error' | 'warn' | 'info' | 'debug';

interface LogEntry {
  level: LogLevel;
  message: string;
  error?: unknown;
  extra?: Record<string, unknown>;
  timestamp: string;
}

// Patterns to identify and redact sensitive data
const SENSITIVE_PATTERNS = [
  /password/gi,
  /token/gi,
  /secret/gi,
  /api[_-]?key/gi,
  /authorization/gi,
  /auth[_-]?token/gi,
  /access[_-]?token/gi,
  /refresh[_-]?token/gi,
  /credit[_-]?card/gi,
  /card[_-]?number/gi,
  /cvv/gi,
  /cvc/gi,
  /ssn/gi,
  /social[_-]?security/gi,
];

const REDACTED_VALUE = '[REDACTED]';

class Logger {
  private isDevelopment = import.meta.env.DEV || import.meta.env.MODE === 'development';

  /**
   * Sanitize sensitive data from log entries
   */
  private sanitize(data: unknown): unknown {
    if (!data || typeof data !== 'object') {
      if (typeof data === 'string') {
        // Check if string contains sensitive patterns
        for (const pattern of SENSITIVE_PATTERNS) {
          if (pattern.test(data)) {
            return REDACTED_VALUE;
          }
        }
      }
      return data;
    }

    if (Array.isArray(data)) {
      return data.map(item => this.sanitize(item));
    }

    const sanitized: Record<string, unknown> = {};
    for (const [key, value] of Object.entries(data)) {
      // Check if key indicates sensitive data
      const isSensitiveKey = SENSITIVE_PATTERNS.some(pattern => pattern.test(key));
      
      if (isSensitiveKey) {
        sanitized[key] = REDACTED_VALUE;
      } else if (typeof value === 'object' && value !== null) {
        sanitized[key] = this.sanitize(value);
      } else if (typeof value === 'string') {
        // Check if value contains sensitive patterns
        const isSensitiveValue = SENSITIVE_PATTERNS.some(pattern => pattern.test(value));
        sanitized[key] = isSensitiveValue ? REDACTED_VALUE : value;
      } else {
        sanitized[key] = value;
      }
    }

    return sanitized;
  }

  /**
   * Sanitize error objects
   */
  private sanitizeError(error: unknown): unknown {
    if (!error) return error;
    
    if (error instanceof Error) {
      const sanitizedError: Record<string, unknown> = {
        name: error.name,
        message: this.sanitize(error.message),
      };
      
      // Sanitize stack trace in production
      if (this.isDevelopment && error.stack) {
        sanitizedError.stack = error.stack;
      }
      
      return sanitizedError;
    }
    
    return this.sanitize(error);
  }

  private log(level: LogLevel, message: string, error?: unknown, extra?: Record<string, unknown>) {
    // Sanitize all data before logging
    const sanitizedMessage = typeof message === 'string' 
      ? (SENSITIVE_PATTERNS.some(p => p.test(message)) ? REDACTED_VALUE : message)
      : message;
    const sanitizedError = this.sanitizeError(error);
    const sanitizedExtra = extra ? this.sanitize(extra) : undefined;

    const entry: LogEntry = {
      level,
      message: sanitizedMessage as string,
      error: sanitizedError,
      extra: sanitizedExtra,
      timestamp: new Date().toISOString(),
    };

    // In development, log to console (with sanitization)
    if (this.isDevelopment) {
      switch (level) {
        case 'error':
          console.error(`[${entry.timestamp}] ERROR: ${entry.message}`, sanitizedError || '', sanitizedExtra || '');
          break;
        case 'warn':
          console.warn(`[${entry.timestamp}] WARN: ${entry.message}`, sanitizedExtra || '');
          break;
        case 'info':
          console.info(`[${entry.timestamp}] INFO: ${entry.message}`, sanitizedExtra || '');
          break;
        case 'debug':
          console.debug(`[${entry.timestamp}] DEBUG: ${entry.message}`, sanitizedExtra || '');
          break;
      }
    }

    // In production, you could send to a logging service
    // Example: sendToLoggingService(entry);
  }

  error(message: string, error?: unknown, extra?: Record<string, unknown>) {
    this.log('error', message, error, extra);
    // In production, could send to error tracking service (e.g., Sentry)
    // if (window.Sentry) {
    //   window.Sentry.captureException(error || new Error(message), { extra });
    // }
  }

  warn(message: string, extra?: Record<string, unknown>) {
    this.log('warn', message, undefined, extra);
  }

  info(message: string, extra?: Record<string, unknown>) {
    this.log('info', message, undefined, extra);
  }

  debug(message: string, extra?: Record<string, unknown>) {
    this.log('debug', message, undefined, extra);
  }
}

export const logger = new Logger();

