import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';

/// AppLogger is a singleton class that provides centralized logging functionality
/// throughout the application using the logger package.
class AppLogger {
  // Private constructor
  AppLogger._internal();

  // Singleton instance
  static final AppLogger _instance = AppLogger._internal();

  // Factory constructor to return the singleton instance
  factory AppLogger() => _instance;

  // Logger instance
  late final Logger _logger;

  // Initialize the logger with custom configuration
  void init({Level? logLevel, bool? stackTraceEnabled}) {
    _logger = Logger(
      level: logLevel ?? (kDebugMode ? Level.debug : Level.info),
      printer: PrettyPrinter(
        methodCount: stackTraceEnabled ?? false ? 2 : 0,
        errorMethodCount: 8,
        lineLength: 120,
        colors: true,
        printEmojis: true,
        dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart,
      ),
      output: _CustomConsoleOutput(),
      filter: _CustomLogFilter(),
    );
  }

  // Get the logger instance (for advanced usage)
  Logger get logger => _logger;

  // Convenient logging methods
  void debug(message, {error, StackTrace? stackTrace}) {
    _logger.d(message, error: error, stackTrace: stackTrace);
  }

  void info(message, {error, StackTrace? stackTrace}) {
    _logger.i(message, error: error, stackTrace: stackTrace);
  }

  void warning(message, {error, StackTrace? stackTrace}) {
    _logger.w(message, error: error, stackTrace: stackTrace);
  }

  void error(message, {error, StackTrace? stackTrace}) {
    _logger.e(message, error: error, stackTrace: stackTrace);
  }

  void fatal(message, {error, StackTrace? stackTrace}) {
    _logger.f(message, error: error, stackTrace: stackTrace);
  }

  // Network logging
  void logNetwork({
    required String method,
    required String url,
    int? statusCode,
    requestBody,
    responseBody,
    error,
  }) {
    final buffer = StringBuffer();
    buffer.writeln('🌐 Network Request:');
    buffer.writeln('   Method: $method');
    buffer.writeln('   URL: $url');

    if (statusCode != null) {
      buffer.writeln('   Status: $statusCode');
    }

    if (requestBody != null) {
      buffer.writeln('   Request Body: $requestBody');
    }

    if (responseBody != null) {
      buffer.writeln('   Response: $responseBody');
    }

    if (error != null) {
      buffer.writeln('   Error: $error');
    }

    if (error != null) {
      _logger.e(buffer.toString());
    } else if (statusCode != null && statusCode >= 400) {
      _logger.w(buffer.toString());
    } else {
      _logger.i(buffer.toString());
    }
  }

  // Performance logging
  void logPerformance(String operation, Duration duration) {
    final milliseconds = duration.inMilliseconds;
    final message = '⏱️  Performance: $operation took ${milliseconds}ms';

    if (milliseconds > 1000) {
      _logger.w(message);
    } else {
      _logger.d(message);
    }
  }

  // Navigation logging
  void logNavigation(String from, String to) {
    _logger.i('🧭 Navigation: $from → $to');
  }

  // Custom log with tag
  void logWithTag(String tag, message, {Level? level}) {
    final taggedMessage = '[$tag] $message';

    switch (level ?? Level.info) {
      case Level.debug:
        debug(taggedMessage);
        break;
      case Level.info:
        info(taggedMessage);
        break;
      case Level.warning:
        warning(taggedMessage);
        break;
      case Level.error:
        error(taggedMessage);
        break;
      case Level.fatal:
        fatal(taggedMessage);
        break;
      default:
        info(taggedMessage);
    }
  }

  // Close the logger (call this in app disposal if needed)
  void close() {
    _logger.close();
  }
}

/// Custom log filter to control which logs are shown
class _CustomLogFilter extends LogFilter {
  @override
  bool shouldLog(LogEvent event) {
    // In debug mode, show all logs
    if (kDebugMode) {
      return true;
    }

    // In release mode, only show warnings and above
    return event.level.value >= Level.warning.value;
  }
}

/// Custom console output for better control over log output
class _CustomConsoleOutput extends ConsoleOutput {
  @override
  void output(OutputEvent event) {
    // You can customize how logs are output here
    // For example, you could write to a file in addition to console
    super.output(event);

    // Example: Write errors to a file (uncomment if needed)
    // if (event.level == Level.error || event.level == Level.fatal) {
    //   _writeToFile(event.lines.join('\n'));
    // }
  }

  // Example method for writing to file (implement if needed)
  // Future<void> _writeToFile(String log) async {
  //   // Implementation for file writing
  // }
}

// Global logger instance for easy access
final appLogger = AppLogger();

// Extension for convenient logging on any object
extension LoggerExtension on Object {
  void logDebug([String? message]) {
    appLogger.debug(message ?? toString());
  }

  void logInfo([String? message]) {
    appLogger.info(message ?? toString());
  }

  void logWarning([String? message]) {
    appLogger.warning(message ?? toString());
  }

  void logError([String? message, error, StackTrace? stackTrace]) {
    appLogger.error(
      message ?? toString(),
      error: error,
      stackTrace: stackTrace,
    );
  }
}
