/**
 * Logger estructurado para la aplicación
 * 
 * Características:
 * - Niveles de log (debug, info, warn, error)
 * - Formato consistente con timestamp y contexto
 * - Configuración por entorno (más verbose en desarrollo)
 * - Fácil de extender para envío a servicios externos
 */

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

export interface LogContext {
  [key: string]: unknown;
  userId?: string;
  requestId?: string;
  module?: string;
}

interface LogEntry {
  timestamp: string;
  level: LogLevel;
  module: string;
  message: string;
  context?: LogContext;
  error?: Error;
}

class Logger {
  private minLevel: LogLevel;
  private enabled: boolean;

  constructor(minLevel: LogLevel = 'info', enabled = true) {
    this.minLevel = minLevel;
    this.enabled = enabled;
  }

  /**
   * Determina si un nivel debe ser logueado
   */
  private shouldLog(level: LogLevel): boolean {
    if (!this.enabled) return false;
    
    const levels: LogLevel[] = ['debug', 'info', 'warn', 'error'];
    const minIndex = levels.indexOf(this.minLevel);
    const currentIndex = levels.indexOf(level);
    
    return currentIndex >= minIndex;
  }

  /**
   * Formatea y escribe el log
   */
  private log(level: LogLevel, module: string, message: string, context?: LogContext, error?: Error) {
    if (!this.shouldLog(level)) return;

    const entry: LogEntry = {
      timestamp: new Date().toISOString(),
      level,
      module,
      message,
      context,
      error,
    };

    const emoji = this.getEmoji(level);
    const color = this.getColor(level);
    
    // Formato para consola
    const logMessage = `${emoji} [${entry.timestamp}] [${level.toUpperCase()}] [${module}] ${message}`;
    
    // Agregar contexto si existe
    if (context && Object.keys(context).length > 0) {
      console[color](logMessage, context);
    } else if (error) {
      console[color](logMessage, error);
    } else {
      console[color](logMessage);
    }

    // En producción, también enviar a servicio de monitoreo si está configurado
    if (process.env.NODE_ENV === 'production') {
      this.sendToMonitoring(entry);
    }
  }

  /**
   * Obtiene emoji para el nivel
   */
  private getEmoji(level: LogLevel): string {
    const emojis: Record<LogLevel, string> = {
      debug: '🐛',
      info: 'ℹ️',
      warn: '⚠️',
      error: '❌',
    };
    return emojis[level];
  }

  /**
   * Obtiene método de consola para el nivel
   */
  private getColor(level: LogLevel): 'log' | 'info' | 'warn' | 'error' {
    const colors: Record<LogLevel, 'log' | 'info' | 'warn' | 'error'> = {
      debug: 'log',
      info: 'info',
      warn: 'warn',
      error: 'error',
    };
    return colors[level];
  }

  /**
   * Envía log a servicio de monitoreo (implementar según necesidad)
   */
  private sendToMonitoring(entry: LogEntry) {
    // TODO: Implementar envío a servicio externo (Sentry, Datadog, etc.)
    // Por ahora, solo logueamos errores en producción
    if (entry.level === 'error') {
      console.error(`[MONITORING] ${entry.module}: ${entry.message}`, entry.error);
    }
  }

  // Métodos públicos para cada nivel

  debug(module: string, message: string, context?: LogContext) {
    this.log('debug', module, message, context);
  }

  info(module: string, message: string, context?: LogContext) {
    this.log('info', module, message, context);
  }

  warn(module: string, message: string, context?: LogContext) {
    this.log('warn', module, message, context);
  }

  error(module: string, message: string, error?: Error, context?: LogContext) {
    this.log('error', module, message, context, error);
  }

  /**
   * Crea un logger con contexto predefinido
   */
  child(context: LogContext): ChildLogger {
    return new ChildLogger(this, context);
  }
}

/**
 * Logger hijo con contexto predefinido
 */
class ChildLogger {
  constructor(
    private parent: Logger,
    private context: LogContext
  ) {}

  debug(module: string, message: string, additionalContext?: LogContext) {
    this.parent.debug(module, message, { ...this.context, ...additionalContext });
  }

  info(module: string, message: string, additionalContext?: LogContext) {
    this.parent.info(module, message, { ...this.context, ...additionalContext });
  }

  warn(module: string, message: string, additionalContext?: LogContext) {
    this.parent.warn(module, message, { ...this.context, ...additionalContext });
  }

  error(module: string, message: string, error?: Error, additionalContext?: LogContext) {
    this.parent.error(module, message, error, { ...this.context, ...additionalContext });
  }
}

/**
 * Factory para crear loggers configurados
 */
export function createLogger(options?: {
  level?: LogLevel;
  enabled?: boolean;
}): Logger {
  const isDevelopment = process.env.NODE_ENV === 'development';
  const isTest = process.env.NODE_ENV === 'test';

  // En tests, desactivamos logs por defecto
  if (isTest) {
    return new Logger('error', false);
  }

  // En desarrollo, mostramos debug
  if (isDevelopment) {
    return new Logger('debug', options?.enabled ?? true);
  }

  // En producción, solo info y arriba
  return new Logger('info', options?.enabled ?? true);
}

// Logger por defecto para la aplicación
export const logger = createLogger();

// Exportar tipos útiles
export type { Logger as ILogger };
