makeApiCall method

Future<ApiCallResponse> makeApiCall({
  1. required String apiUrl,
  2. required BuildContext context,
  3. required ApiCallType callType,
  4. Map<String, dynamic> headers = const {},
  5. Map<String, dynamic> params = const {},
  6. String? body,
  7. BodyType? bodyType = BodyType.JSON,
  8. bool returnBody = true,
  9. bool encodeBodyUtf8 = false,
  10. bool decodeUtf8 = false,
  11. bool needAuth = false,
  12. bool needTenant = false,
  13. bool showSuccessMessage = false,
  14. bool showErrorMessage = true,
  15. String? successMessage,
  16. bool replaceApiUrl = false,
  17. String? completeApiUrl,
})

Implementation

Future<ApiCallResponse> makeApiCall({
  required String apiUrl,
  required BuildContext context,
  required ApiCallType callType,
  Map<String, dynamic> headers = const {},
  Map<String, dynamic> params = const {},
  String? body,
  BodyType? bodyType = BodyType.JSON,
  bool returnBody = true,
  bool encodeBodyUtf8 = false,
  bool decodeUtf8 = false,
  bool needAuth = false,
  bool needTenant = false,
  bool showSuccessMessage = false,
  bool showErrorMessage = true,
  String? successMessage,
  bool replaceApiUrl = false,
  String? completeApiUrl,
}) async {
  // Short-circuit if the calling widget's context has been deactivated
  // (e.g. user navigated away while an init chain was about to fire).
  // Avoids wasted HTTP traffic + JSON decode + downstream Provider lookups
  // that would throw on a dead Element.
  if (!context.mounted) {
    return const ApiCallResponse(null, null, null, {}, 0);
  }
  headers = await initHeader(headers, needAuth, needTenant, context);

  // Se replaceApiUrl è true e c'è completeApiUrl, usa quello
  if (replaceApiUrl && completeApiUrl != null && completeApiUrl.isNotEmpty) {
    apiUrl = completeApiUrl;
  } else {
    apiUrl = _baseUrl + _apiVersion + apiUrl;
    if (!apiUrl.startsWith('http')) {
      apiUrl = 'https://$apiUrl';
    }
  }
  ApiCallResponse result;

  // === DEBUG LOG: Richiesta ===
  assert(() {
    final method = callType.name;
    debugPrint('┌── API REQUEST ──────────────────────────────');
    debugPrint('│ $method $apiUrl');
    if (params.isNotEmpty) {
      final paramsStr = Map<String, dynamic>.from(params).toString();
      debugPrint('│ Params: ${paramsStr.length > 200 ? '${paramsStr.substring(0, 200)}...' : paramsStr}');
    }
    if (body != null) {
      debugPrint('│ Body: ${body.length > 200 ? '${body.substring(0, 200)}...' : body}');
    }
    debugPrint('└─────────────────────────────────────────────');
    return true;
  }());

  switch (callType) {
    case ApiCallType.GET:
    case ApiCallType.DELETE:
      result = await urlRequest(callType, apiUrl, headers, params, returnBody, decodeUtf8);
      break;
    case ApiCallType.POST:
    case ApiCallType.PUT:
    case ApiCallType.PATCH:
      result = await requestWithBody(callType, apiUrl, headers, params, body, bodyType, returnBody, encodeBodyUtf8, decodeUtf8);
      break;
  }

  // === DEBUG LOG: Risposta ===
  assert(() {
    final method = callType.name;
    final statusIcon = result.succeeded ? '✅' : '❌';
    debugPrint('┌── API RESPONSE ─────────────────────────────');
    debugPrint('│ $statusIcon $method $apiUrl');
    debugPrint('│ Status: ${result.statusCode}');
    if (result.error != null) {
      debugPrint('│ Error: ${result.error?.message ?? result.error?.error}');
    }
    if (!result.succeeded) {
      final rawBody = result.bodyText;
      debugPrint('│ Raw Body: ${rawBody.length > 500 ? '${rawBody.substring(0, 500)}...' : rawBody}');
    }
    if (result.jsonBody != null) {
      final bodyStr = result.jsonBody.toString();
      debugPrint('│ Body: ${bodyStr.length > 500 ? '${bodyStr.substring(0, 500)}...' : bodyStr}');
    }
    if (result.pagination != null) {
      debugPrint(
        '│ Pagination: page=${result.pagination?.currentPage}, total=${result.pagination?.total}, lastPage=${result.pagination?.lastPage}',
      );
    }
    debugPrint('└─────────────────────────────────────────────');
    return true;
  }());

  if (result.succeeded) {
    if (showSuccessMessage) {
      AlertManager.showSuccess("Successo", successMessage ?? "Operazione completata con successo", alertPosition: AlertPosition.bottom);
    }
  } else {
    // Gestisci 401 e 403 tramite ErrorState e redirect
    _handleResponse(result, context);

    // Non mostrare alert per 401 e 403, vengono gestiti dalla pagina di errore
    if (result.statusCode != 401 && result.statusCode != 403 && showErrorMessage) {
      AlertManager.showDanger(
        result.error?.error?.toString() ?? "Errore ${result.statusCode}",
        result.error?.message ?? "Si è verificato un errore durante l'operazione",
        alertPosition: AlertPosition.bottom,
      );
    }
  }
  return result;
}