
/**
 * Advanced Error Logging and Monitoring Service
 */

import { AppError } from './error-handler';

export type ErrorSeverity = 'low' | 'medium' | 'high' | 'critical';

export interface ErrorLog {
  id: string;
  timestamp: Date;
  severity: ErrorSeverity;
  message: string;
  stack?: string;
  context?: string;
  userAgent?: string;
  url?: string;
  userId?: string;
  metadata?: Record<string, any>;
}

class ErrorLogger {
  private logs: ErrorLog[] = [];
  private maxLogs: number = 1000;
  private listeners: Array<(log: ErrorLog) => void> = [];

  log(
    error: Error | AppError | string,
    context?: string,
    severity: ErrorSeverity = 'medium',
    metadata?: Record<string, any>
  ) {
    const errorLog: ErrorLog = {
      id: `error-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      timestamp: new Date(),
      severity,
      message: typeof error === 'string' ? error : error.message,
      stack: typeof error === 'object' ? error.stack : undefined,
      context,
      userAgent: typeof window !== 'undefined' ? window.navigator.userAgent : undefined,
      url: typeof window !== 'undefined' ? window.location.href : undefined,
      metadata,
    };

    // Store log
    this.logs.push(errorLog);

    // Trim logs if exceeding max
    if (this.logs.length > this.maxLogs) {
      this.logs = this.logs.slice(-this.maxLogs);
    }

    // Notify listeners
    this.listeners.forEach(listener => {
      try {
        listener(errorLog);
      } catch (err) {
        console.error('Error in error logger listener:', err);
      }
    });

    // Console output
    this.outputToConsole(errorLog);

    // Send to external service if critical
    if (severity === 'critical') {
      this.sendToExternalService(errorLog);
    }

    return errorLog;
  }

  private outputToConsole(log: ErrorLog) {
    const style = this.getSeverityStyle(log.severity);
    const prefix = `[${log.severity.toUpperCase()}] ${log.timestamp.toISOString()}`;
    
    if (log.context) {
      console.error(`${prefix} [${log.context}]:`, log.message);
    } else {
      console.error(`${prefix}:`, log.message);
    }

    if (log.stack) {
      console.error('Stack trace:', log.stack);
    }

    if (log.metadata) {
      console.error('Metadata:', log.metadata);
    }
  }

  private getSeverityStyle(severity: ErrorSeverity): string {
    switch (severity) {
      case 'low':
        return 'color: #3b82f6'; // blue
      case 'medium':
        return 'color: #f59e0b'; // amber
      case 'high':
        return 'color: #ef4444'; // red
      case 'critical':
        return 'color: #dc2626; font-weight: bold'; // dark red, bold
      default:
        return '';
    }
  }

  private async sendToExternalService(log: ErrorLog) {
    // In production, send to services like Sentry, LogRocket, etc.
    try {
      // Example: await fetch('/api/error-reporting', { method: 'POST', body: JSON.stringify(log) });
      console.log('Would send to external error tracking service:', log);
    } catch (err) {
      console.error('Failed to send error to external service:', err);
    }
  }

  // Subscribe to error logs
  subscribe(listener: (log: ErrorLog) => void): () => void {
    this.listeners.push(listener);
    
    // Return unsubscribe function
    return () => {
      const index = this.listeners.indexOf(listener);
      if (index > -1) {
        this.listeners.splice(index, 1);
      }
    };
  }

  // Get logs by severity
  getLogsBySeverity(severity: ErrorSeverity): ErrorLog[] {
    return this.logs.filter(log => log.severity === severity);
  }

  // Get logs by context
  getLogsByContext(context: string): ErrorLog[] {
    return this.logs.filter(log => log.context === context);
  }

  // Get recent logs
  getRecentLogs(count: number = 50): ErrorLog[] {
    return this.logs.slice(-count);
  }

  // Get all logs
  getAllLogs(): ErrorLog[] {
    return [...this.logs];
  }

  // Clear logs
  clear() {
    this.logs = [];
  }

  // Get error statistics
  getStatistics() {
    const total = this.logs.length;
    const bySeverity = {
      low: this.logs.filter(l => l.severity === 'low').length,
      medium: this.logs.filter(l => l.severity === 'medium').length,
      high: this.logs.filter(l => l.severity === 'high').length,
      critical: this.logs.filter(l => l.severity === 'critical').length,
    };

    const byContext: Record<string, number> = {};
    this.logs.forEach(log => {
      if (log.context) {
        byContext[log.context] = (byContext[log.context] || 0) + 1;
      }
    });

    return {
      total,
      bySeverity,
      byContext,
    };
  }
}

// Global error logger instance
export const errorLogger = new ErrorLogger();

// Setup global error handlers
if (typeof window !== 'undefined') {
  window.addEventListener('error', (event) => {
    errorLogger.log(
      event.error || event.message,
      'window.error',
      'high',
      {
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno,
      }
    );
  });

  window.addEventListener('unhandledrejection', (event) => {
    errorLogger.log(
      event.reason,
      'unhandledRejection',
      'high',
      {
        promise: event.promise,
      }
    );
  });
}

// Helper functions
export function logError(
  error: Error | string,
  context?: string,
  metadata?: Record<string, any>
) {
  return errorLogger.log(error, context, 'medium', metadata);
}

export function logWarning(
  message: string,
  context?: string,
  metadata?: Record<string, any>
) {
  return errorLogger.log(message, context, 'low', metadata);
}

export function logCritical(
  error: Error | string,
  context?: string,
  metadata?: Record<string, any>
) {
  return errorLogger.log(error, context, 'critical', metadata);
}
