import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:logger/logger.dart';

class LoggerInterceptor extends Interceptor {
  // Configs
  final bool prettyPrintJson = false; // Mặc định: JSON 1 dòng dễ copy/paste
  final bool chunkLogging = true;     // Chia nhỏ log theo block để tránh bị cắt
  final int chunkSize = 800;         // Kích thước mỗi block

  final Logger _logger = Logger(
    printer: PrettyPrinter(
      methodCount: 0,
      lineLength: 120,
      printTime: true,
      colors: true,
    ),
  );

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    final uri = options.uri;
    final buffer = StringBuffer();
    buffer.writeln('🚀 ${options.method} $uri');
    buffer.writeln('Headers: ${_formatHeaders(options.headers)}');
    if (options.queryParameters.isNotEmpty) {
      buffer.writeln('Query: ${_stringify(options.queryParameters)}');
    }
    _emit(Level.info, 'REQUEST', uri.toString(), buffer.toString());
    if (options.data != null) {
      final bodyString = _stringify(options.data);
      _emitJsonBlocks(Level.info, 'REQUEST JSON', uri.toString(), bodyString);
    }
    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    final uri = response.requestOptions.uri;
    final statusCode = response.statusCode;
    final buffer = StringBuffer();
    buffer.writeln('✅ $statusCode ${response.requestOptions.method} $uri');
    if (response.headers.map.isNotEmpty) {
      buffer.writeln('Resp Headers: ${_stringify(response.headers.map)}');
    }
    _emit(Level.debug, 'RESPONSE', uri.toString(), buffer.toString());
    // emit body in copy-friendly blocks
    final bodyString = _stringify(response.data);
    _emitJsonBlocks(Level.debug, 'RESPONSE JSON', uri.toString(), bodyString);
    handler.next(response);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    final uri = err.requestOptions.uri;
    final statusCode = err.response?.statusCode ?? 'Unknown';
    final buffer = StringBuffer();
    buffer.writeln('❌ $statusCode ${err.requestOptions.method} $uri');
    buffer.writeln('Error: ${err.message}');
    _emit(Level.error, 'ERROR', uri.toString(), buffer.toString());
    if (err.response?.data != null) {
      final bodyString = _stringify(err.response?.data);
      _emitJsonBlocks(Level.error, 'ERROR JSON', uri.toString(), bodyString);
    }
    handler.next(err);
  }

  String _formatHeaders(Map<String, dynamic> headers) {
    final filtered = Map<String, dynamic>.from(headers);
    // Hide sensitive headers
    if (filtered.containsKey('Authorization')) {
      filtered['Authorization'] = '***';
    }
    return filtered.toString();
  }

  String _stringify(dynamic data) {
    if (data == null) return 'null';
    if (data is String) return data;
    try {
      if (prettyPrintJson) {
        final encoder = const JsonEncoder.withIndent('  ');
        return encoder.convert(data);
      }
      return jsonEncode(data);
    } catch (_) {
      return data.toString();
    }
  }

  void _emit(Level level, String phase, String uri, String message) {
    if (!chunkLogging || message.length <= chunkSize) {
      _logger.log(level, '[$phase] $uri\n$message');
      return;
    }
    final total = (message.length / chunkSize).ceil();
    var index = 0;
    for (var i = 0; i < message.length; i += chunkSize) {
      final end = (i + chunkSize < message.length) ? i + chunkSize : message.length;
      index += 1;
      _logger.log(level, '[$phase PART $index/$total] $uri\n${message.substring(i, end)}');
    }
  }

  void _emitJsonBlocks(Level level, String phase, String uri, String jsonText) {
    if (!chunkLogging || jsonText.length <= chunkSize) {
      _logger.log(level, '[$phase FULL] $uri');
      _logger.log(level, jsonText);
      return;
    }
    final total = (jsonText.length / chunkSize).ceil();
    var index = 0;
    for (var i = 0; i < jsonText.length; i += chunkSize) {
      final end = (i + chunkSize < jsonText.length) ? i + chunkSize : jsonText.length;
      index += 1;
      _logger.log(level, '[$phase PART $index/$total] $uri');
      _logger.log(level, jsonText.substring(i, end));
    }
  }
}