request method

Future<ResponseModal> request({
  1. required ApiMethod method,
  2. required String url,
  3. dynamic requestData,
  4. Map<String, dynamic>? headers,
  5. void authTokenCallback()?,
  6. Map<String, dynamic>? queryParameters,
  7. bool useWithoutToken = false,
  8. bool cacheResponse = false,
  9. Duration cacheDuration = const Duration(minutes: 30),
  10. bool forceOffline = false,
  11. CancelToken? cancelToken,
  12. void onSendProgress(
    1. int,
    2. int
    )?,
  13. void onReceiveProgress(
    1. int,
    2. int
    )?,
  14. BuildContext? context,
  15. bool showSuccessMessage = false,
  16. bool showErrorMessage = true,
  17. bool showErrorLog = true,
  18. bool showSuccessLog = true,
})

Implementation

Future<ResponseModal> request({
  required ApiMethod method,
  required String url,
  dynamic requestData,
  Map<String, dynamic>? headers,
  void Function()? authTokenCallback,
  Map<String, dynamic>? queryParameters,
  bool useWithoutToken = false,
  bool cacheResponse = false,
  Duration cacheDuration = const Duration(minutes: 30),
  bool forceOffline = false,
  CancelToken? cancelToken,
  void Function(int, int)? onSendProgress,
  void Function(int, int)? onReceiveProgress,
  BuildContext? context,
  bool showSuccessMessage = false,
  bool showErrorMessage = true,
  bool showErrorLog = true,
  bool showSuccessLog = true,
}) async
{
  try {
    // Check if we should force offline mode
    if (forceOffline) {
      print('Force offline mode enabled');
      if (!_enableCache) {
        print('Cache not enabled, cannot use offline mode');
        throw {'error': 'Cache not enabled, cannot use offline mode'};
      }
      final cached = _cacheBox.get(url);
      if (cached != null) return cached['data'] ?? cached;
      print('No cached data available');
      throw {'error': 'No cached data available'};
    }

    // Make the request
    late Response response;
    final options = Options(
      headers: headers,
      extra: {
        'useWithoutToken': useWithoutToken,
        'cacheResponse': cacheResponse,
        'cacheDuration': cacheDuration.inMilliseconds,
      },
    );

    switch (method) {
      case ApiMethod.get:
        response = await _dio.get(
          url,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
          onReceiveProgress: onReceiveProgress,
        );
        break;
      case ApiMethod.post:
        response = await _dio.post(
          url,
          data: requestData,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
          onSendProgress: onSendProgress,
        );
        break;
      case ApiMethod.put:
        response = await _dio.put(
          url,
          data: requestData,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
          onSendProgress: onSendProgress,
        );
        break;
      case ApiMethod.patch:
        response = await _dio.patch(
          url,
          data: requestData,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
          onSendProgress: onSendProgress,
        );
        break;
      case ApiMethod.delete:
        response = await _dio.delete(
          url,
          data: requestData,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken,
        );
        break;
    }

    // Cache response if needed
    if (_enableCache && cacheResponse) {
      await _cacheBox.put(
        url,
        response.data,
      );
    }
    final responseModal = ResponseModal.fromDioResponse(response);
    if (showSuccessLog) {
      log('Response is ${responseModal.data}');
    }
    log('loklklklklkl is ${responseModal.data}');

    if (responseModal.status == 1 && showSuccessMessage) {
      _showSnackbar(context, responseModal.message, isError: false);
    } else if (responseModal.status == 0 && showErrorMessage) {
      _showSnackbar(context, responseModal.message, isError: true);
    }

    return responseModal;
  } on DioException catch (e) {
    // Create a detailed error log message
//     final errorLog = '''
// ╔═══════════════════════════════════════════════════════════════
// ║ Dio Exception Occurred
// ╟───────────────────────────────────────────────────────────────
// ║ Type: ${}
// ║ Error: ${e.error}
// ║ Message: ${e.message}
// �═══════════════════════════════════════════════════════════════
// ║ Request:
// ║   URL: ${e.requestOptions.uri}
// ║   Method: ${e.requestOptions.method}
// ║   Headers: ${e.requestOptions.headers}
// ╟───────────────────────────────────────────────────────────────
// ║ Response:
// ║   Status: ${e.response?.statusCode}
// ║   Data: ${e.response?.data}
// ║   Headers: ${e.response?.headers}
// ╚═══════════════════════════════════════════════════════════════
// ''';

    if (showErrorLog) {
      log("Dio Exception Message: ${e.message}, ");
      log("Dio Exception Occurred Error: ${e.error}, Status: ${e.response?.statusCode}, Data: ${e.response?.data},  ");
    }

    // Handle response errors
    if (e.response != null) {
      try {
        final errorResponse = e.response?.data;
        final statusCode = e.response?.statusCode;

        // Special handling for 401 Unauthorized
        if (statusCode == 401) {
          authTokenCallback?.call();
          log(
              '⚠️ Authorization failed. Status: 401. Response: $errorResponse');

          final message = errorResponse is Map
              ? errorResponse['message'] ??
              'Session expired. Please login again.'
              : 'Session expired. Please login again.';

          if (showErrorMessage) {
            _showSnackbar(context, message, isError: true);
          }

          return ResponseModal(
            message: message,
            data: errorResponse is Map ? (errorResponse['data'] ?? {}) : {},
            status: 0,
            error: errorResponse is Map ? (errorResponse['error'] ??
                {'code': 'unauthorized'}) : {'code': 'unauthorized'},
            fullData: errorResponse ?? {},
          );
        }

        // Handle other error responses with message
        if (errorResponse is Map) {
          final message = errorResponse['message'] ??
              errorResponse['error']?['hint'] ??
              'Request failed with status $statusCode';

          if (showErrorMessage) {
            _showSnackbar(context, message, isError: true);
          }

          return ResponseModal(
            message: message,
            data: errorResponse['data'] ?? {},
            status: errorResponse['status'] ?? 0,
            error: errorResponse['error'] ??
                {'code': 'unknown_error', 'status': statusCode},
            fullData: errorResponse,
          );
        }
      } catch (parseError) {
        log('❌ Error parsing error response: $parseError');
      }
    }

    // Handle specific error types
    switch (e.type) {
      case DioExceptionType.connectionError:
        _showSnackbar(context, 'No internet connection');
        return ResponseModal(
          message: 'No internet connection',
          data: {},
          status: 0,
          error: {'code': 'no_internet'},
          fullData: {},
        );

      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        _showSnackbar(context, 'Request timeout. Please try again.');
        return ResponseModal(
          message: 'Request timeout',
          data: {},
          status: 0,
          error: {'code': 'timeout'},
          fullData: {},
        );

      case DioExceptionType.badCertificate:
        log('🔒 SSL Certificate Error: ${e.error}');
        _showSnackbar(context, 'Secure connection failed');
        return ResponseModal(
          message: 'Secure connection failed',
          data: {},
          status: 0,
          error: {'code': 'ssl_error', 'details': e.error.toString()},
          fullData: {},
        );

      default:
        final userMessage = kDebugMode
            ? e.message ?? 'An error occurred'
            : 'Something went wrong. Please try again.';

        if (kDebugMode) {
          _showSnackbar(context, userMessage, isError: true);
        }

        return ResponseModal(
          message: userMessage,
          data: {},
          status: 0,
          error: {
            'code': 'unknown_error',
            'type': e.type.toString(),
            'details': e.error?.toString()
          },
          fullData: e.response?.data ?? {},
        );
    }
  } catch (e, stackTrace) {
    log('''
╔═══════════════════════════════════════════════════════════════
║ Unhandled Exception
╟───────────────────────────────────────────────────────────────
║ Error: $e
║ Stack Trace: $stackTrace
╚═══════════════════════════════════════════════════════════════
''');

    final errorModal = ResponseModal(
      message: kDebugMode ? e.toString() : 'An unexpected error occurred',
      data: {},
      status: 0,
      error: {
        'code': 'unhandled_exception',
        'details': e.toString(),
        'stackTrace': kDebugMode ? stackTrace.toString() : null
      },
      fullData: {},
    );

    if (kDebugMode) {
      _showSnackbar(context, e.toString());
    }

    return errorModal;
  }
}