/// Logger centralisé pour l'application
library logger;

import 'package:flutter/foundation.dart';
import '../config/environment.dart';

/// Niveaux de log
enum LogLevel {
  debug,
  info,
  warning,
  error,
  fatal,
}

/// Logger centralisé pour toute l'application
class AppLogger {
  // Empêcher l'instanciation
  AppLogger._();

  /// Couleurs ANSI pour les logs en console
  static const String _reset = '\x1B[0m';
  static const String _red = '\x1B[31m';
  static const String _green = '\x1B[32m';
  static const String _yellow = '\x1B[33m';
  static const String _blue = '\x1B[34m';
  static const String _magenta = '\x1B[35m';
  static const String _cyan = '\x1B[36m';
  static const String _white = '\x1B[37m';

  /// Log de niveau DEBUG (bleu)
  static void debug(String message, {String? tag}) {
    if (AppConfig.enableLogging && kDebugMode) {
      _log(LogLevel.debug, message, tag: tag, color: _blue);
    }
  }

  /// Log de niveau INFO (vert)
  static void info(String message, {String? tag}) {
    if (AppConfig.enableLogging && kDebugMode) {
      _log(LogLevel.info, message, tag: tag, color: _green);
    }
  }

  /// Log de niveau WARNING (jaune)
  static void warning(String message, {String? tag}) {
    if (AppConfig.enableLogging && kDebugMode) {
      _log(LogLevel.warning, message, tag: tag, color: _yellow);
    }
  }

  /// Log de niveau ERROR (rouge)
  static void error(
    String message, {
    String? tag,
    dynamic error,
    StackTrace? stackTrace,
  }) {
    if (AppConfig.enableLogging) {
      _log(LogLevel.error, message, tag: tag, color: _red);
      
      if (error != null) {
        _log(LogLevel.error, 'Error: $error', tag: tag, color: _red);
      }
      
      if (stackTrace != null) {
        _log(LogLevel.error, 'StackTrace:\n$stackTrace', tag: tag, color: _red);
      }

      // Envoi au service de monitoring si configuré
      if (AppConfig.enableCrashReporting) {
        _sendToMonitoring(message, error, stackTrace);
      }
    }
  }

  /// Log de niveau FATAL (magenta)
  static void fatal(
    String message, {
    String? tag,
    dynamic error,
    StackTrace? stackTrace,
  }) {
    if (AppConfig.enableLogging) {
      _log(LogLevel.fatal, message, tag: tag, color: _magenta);
      
      if (error != null) {
        _log(LogLevel.fatal, 'Error: $error', tag: tag, color: _magenta);
      }
      
      if (stackTrace != null) {
        _log(LogLevel.fatal, 'StackTrace:\n$stackTrace', tag: tag, color: _magenta);
      }

      // Envoi au service de monitoring si configuré
      if (AppConfig.enableCrashReporting) {
        _sendToMonitoring(message, error, stackTrace, isFatal: true);
      }
    }
  }

  /// Log d'une requête HTTP
  static void httpRequest({
    required String method,
    required String url,
    Map<String, dynamic>? headers,
    dynamic body,
  }) {
    if (AppConfig.enableLogging && kDebugMode) {
      final buffer = StringBuffer();
      buffer.writeln('┌─────────────────────────────────────────────────');
      buffer.writeln('│ HTTP REQUEST');
      buffer.writeln('├─────────────────────────────────────────────────');
      buffer.writeln('│ Method: $method');
      buffer.writeln('│ URL: $url');
      
      if (headers != null && headers.isNotEmpty) {
        buffer.writeln('│ Headers:');
        headers.forEach((key, value) {
          buffer.writeln('│   $key: $value');
        });
      }
      
      if (body != null) {
        buffer.writeln('│ Body: $body');
      }
      
      buffer.writeln('└─────────────────────────────────────────────────');
      
      _log(LogLevel.debug, buffer.toString(), color: _cyan);
    }
  }

  /// Log d'une réponse HTTP
  static void httpResponse({
    required int statusCode,
    required String url,
    Map<String, dynamic>? headers,
    dynamic body,
    Duration? duration,
  }) {
    if (AppConfig.enableLogging && kDebugMode) {
      final buffer = StringBuffer();
      buffer.writeln('┌─────────────────────────────────────────────────');
      buffer.writeln('│ HTTP RESPONSE');
      buffer.writeln('├─────────────────────────────────────────────────');
      buffer.writeln('│ Status: $statusCode');
      buffer.writeln('│ URL: $url');
      
      if (duration != null) {
        buffer.writeln('│ Duration: ${duration.inMilliseconds}ms');
      }
      
      if (headers != null && headers.isNotEmpty) {
        buffer.writeln('│ Headers:');
        headers.forEach((key, value) {
          buffer.writeln('│   $key: $value');
        });
      }
      
      if (body != null) {
        buffer.writeln('│ Body: $body');
      }
      
      buffer.writeln('└─────────────────────────────────────────────────');
      
      final color = statusCode >= 200 && statusCode < 300 ? _green : _red;
      _log(LogLevel.debug, buffer.toString(), color: color);
    }
  }

  /// Log d'un événement BLoC
  static void blocEvent(String blocName, String eventName, {dynamic data}) {
    if (AppConfig.enableLogging && kDebugMode) {
      final message = data != null
          ? '[$blocName] Event: $eventName | Data: $data'
          : '[$blocName] Event: $eventName';
      _log(LogLevel.debug, message, color: _cyan);
    }
  }

  /// Log d'un changement d'état BLoC
  static void blocState(String blocName, String stateName, {dynamic data}) {
    if (AppConfig.enableLogging && kDebugMode) {
      final message = data != null
          ? '[$blocName] State: $stateName | Data: $data'
          : '[$blocName] State: $stateName';
      _log(LogLevel.debug, message, color: _magenta);
    }
  }

  /// Log d'une navigation
  static void navigation(String from, String to) {
    if (AppConfig.enableLogging && kDebugMode) {
      _log(LogLevel.debug, 'Navigation: $from → $to', color: _yellow);
    }
  }

  /// Log d'une action utilisateur
  static void userAction(String action, {Map<String, dynamic>? data}) {
    if (AppConfig.enableLogging && kDebugMode) {
      final message = data != null
          ? 'User Action: $action | Data: $data'
          : 'User Action: $action';
      _log(LogLevel.info, message, color: _green);
    }

    // Envoi au service d'analytics si configuré
    if (AppConfig.enableAnalytics) {
      _sendToAnalytics(action, data);
    }
  }

  /// Méthode privée pour logger avec formatage
  static void _log(
    LogLevel level,
    String message, {
    String? tag,
    String color = _white,
  }) {
    final timestamp = DateTime.now().toIso8601String();
    final levelStr = level.name.toUpperCase().padRight(7);
    final tagStr = tag != null ? '[$tag] ' : '';
    
    if (kDebugMode) {
      // En mode debug, utiliser les couleurs
      debugPrint('$color$timestamp | $levelStr | $tagStr$message$_reset');
    } else {
      // En mode release, pas de couleurs
      debugPrint('$timestamp | $levelStr | $tagStr$message');
    }
  }

  /// Callback optionnel pour envoyer les erreurs au monitoring (Sentry / Firebase Crashlytics).
  /// À enregistrer au démarrage de l'app quand le SDK est intégré.
  static void Function(String message, dynamic error, StackTrace? stackTrace, {bool isFatal})? onMonitoringReport;

  /// Callback optionnel pour envoyer les événements analytics (Firebase Analytics / Mixpanel).
  /// À enregistrer au démarrage de l'app quand le SDK est intégré.
  static void Function(String action, Map<String, dynamic>? data)? onAnalyticsEvent;

  /// Envoyer les erreurs à un service de monitoring
  static void _sendToMonitoring(
    String message,
    dynamic error,
    StackTrace? stackTrace, {
    bool isFatal = false,
  }) {
    if (onMonitoringReport != null) {
      try {
        onMonitoringReport!(message, error, stackTrace, isFatal: isFatal);
      } catch (e, st) {
        if (kDebugMode) {
          debugPrint('AppLogger: échec envoi monitoring: $e');
          debugPrint('$st');
        }
      }
      return;
    }
    if (kDebugMode && (error != null || stackTrace != null)) {
      debugPrint('AppLogger: monitoring non configuré (enregistrer onMonitoringReport pour Sentry/Crashlytics)');
    }
  }

  /// Envoyer les événements à un service d'analytics
  static void _sendToAnalytics(String action, Map<String, dynamic>? data) {
    if (onAnalyticsEvent != null) {
      try {
        onAnalyticsEvent!(action, data);
      } catch (e, st) {
        if (kDebugMode) {
          debugPrint('AppLogger: échec envoi analytics: $e');
          debugPrint('$st');
        }
      }
      return;
    }
    if (kDebugMode) {
      debugPrint('AppLogger: analytics non configuré (enregistrer onAnalyticsEvent pour Firebase/Mixpanel)');
    }
  }

  /// Divider pour séparer visuellement les logs
  static void divider({String? title}) {
    if (AppConfig.enableLogging && kDebugMode) {
      if (title != null) {
        debugPrint('$_cyan═══════════════════════════════════════════════════$_reset');
        debugPrint('$_cyan  $title$_reset');
        debugPrint('$_cyan═══════════════════════════════════════════════════$_reset');
      } else {
        debugPrint('$_cyan═══════════════════════════════════════════════════$_reset');
      }
    }
  }
}

/// Extension pour faciliter le logging depuis n'importe où
extension LoggerExtension on Object {
  /// Log debug
  void logDebug(String message) {
    AppLogger.debug(message, tag: runtimeType.toString());
  }

  /// Log info
  void logInfo(String message) {
    AppLogger.info(message, tag: runtimeType.toString());
  }

  /// Log warning
  void logWarning(String message) {
    AppLogger.warning(message, tag: runtimeType.toString());
  }

  /// Log error
  void logError(String message, {dynamic error, StackTrace? stackTrace}) {
    AppLogger.error(
      message,
      tag: runtimeType.toString(),
      error: error,
      stackTrace: stackTrace,
    );
  }
}

