import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:clarity_flutter/clarity_flutter.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/api/http_client_manager.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/home/app_update_page.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart';
import 'package:hmg_patient_app_new/services/analytics/analytics_service.dart';
import 'package:hmg_patient_app_new/services/app_lifecycle_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:http/http.dart' as http;

abstract class ApiClient {
  static final NavigationService _navigationService = getIt.get<NavigationService>();

  Future<void> post(
    String endPoint, {
    required Map<String, dynamic> body,
    required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess,
    required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure,
    bool isAllowAny,
    bool isExternal,
    bool isRCService,
    bool isPaymentServices,
    bool bypassConnectionCheck,
    Map<String, String> apiHeaders,
    bool isBodyPlainText,
  });

  Future<void> get(
    String endPoint, {
    required Function(dynamic response, int statusCode) onSuccess,
    required Function(String error, int statusCode) onFailure,
    Map<String, dynamic>? queryParams,
    Map<String, String> apiHeaders,
    bool isAllowAny,
    bool isExternal,
    bool isRCService,
  });

  String getSessionId(String id);

// Future<void> simplePost(
//   String fullUrl, {
//   required Map<dynamic, dynamic> body,
//   required Map<String, String> headers,
//   required Function(dynamic response, int statusCode) onSuccess,
//   required Function(String error, int statusCode) onFailure,
// });

//
// Future<void> simpleGet(
//   String fullUrl, {
//   Function(dynamic response, int statusCode)? onSuccess,
//   Function(String error, int statusCode)? onFailure,
//   Map<String, dynamic>? queryParams,
//   Map<String, String>? headers,
// });
//
// Future<void> simplePut(
//   String fullUrl, {
//   Map<String, dynamic>? body,
//   Map<String, String>? headers,
//   Function(dynamic response, int statusCode)? onSuccess,
//   Function(String error, int statusCode)? onFailure,
// });
//
// Future<void> simpleDelete(
//   String fullUrl, {
//   Function(dynamic response, int statusCode)? onSuccess,
//   Function(String error, int statusCode)? onFailure,
//   Map<String, String>? queryParams,
//   Map<String, String>? headers,
// });

// Future<bool> handleUnauthorized(int statusCode, {required String forUrl});
// Future<String> generatePackagesToken();
}

class ApiClientImp implements ApiClient {
  final _analytics = getIt<GAnalytics>();
  final AppState _appState;
  final HttpClientManager _httpClient;

  ApiClientImp({
    required AppState appState,
    HttpClientManager? httpClient,
  })  : _appState = appState,
        _httpClient = httpClient ?? HttpClientManager(lifecycleService: getIt<AppLifecycleService>());

  @override
  post(
    String endPoint, {
    required dynamic body,
    required Function(dynamic response, int statusCode, {int? messageStatus, String? errorMessage}) onSuccess,
    required Function(String error, int statusCode, {int? messageStatus, Failure? failureType}) onFailure,
    bool isAllowAny = false,
    bool isExternal = false,
    bool isRCService = false,
    bool isPaymentServices = false,
    bool bypassConnectionCheck = true,
    Map<String, String>? apiHeaders,
    bool isBodyPlainText = false,
  }) async {
    String url;
    if (isExternal) {
      url = endPoint;
    } else {
      if (isRCService) {
        url = ApiConsts.rcBaseUrl + endPoint;
      } else {
        url = ApiConsts.baseUrl + endPoint;
      }
    }
    // try {
    var user = _appState.getAuthenticatedUser();
    Map<String, String> headers = apiHeaders ?? {'Content-Type': 'application/json', 'Accept': 'application/json'};

    // When isBodyPlainText is true, skip all body manipulation and use body as-is
    if (!isBodyPlainText) {
      if (!isExternal) {
        String? token = _appState.appAuthToken;

        if (body.containsKey('SetupID')) {
          body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] ?? body[''] : SETUP_ID;
        } else {}

        if (body.containsKey('isDentalAllowedBackend')) {
          body['isDentalAllowedBackend'] =
              body.containsKey('isDentalAllowedBackend') ? body['isDentalAllowedBackend'] ?? IS_DENTAL_ALLOWED_BACKEND : IS_DENTAL_ALLOWED_BACKEND;
        }

        if (!body.containsKey('IsPublicRequest')) {
          // if (!body.containsKey('PatientType')) {
          if (user != null && user.patientType != null) {
            body['PatientType'] = user.patientType;
          } else {
            body['PatientType'] = PATIENT_TYPE.toString();
          }

          if (user != null && user.patientType != null) {
            body['PatientTypeID'] = user.patientType;
          } else {
            body['PatientType'] = PATIENT_TYPE_ID.toString();
          }

          if (user != null) {
            body['TokenID'] = body['TokenID'] ?? token;

            body['PatientID'] = body['PatientID'] ?? user.patientId;

            body['PatientOutSA'] = body.containsKey('PatientOutSA') ? body['PatientOutSA'] ?? user.outSa : user.outSa;
            body['SessionID'] = body['TokenID'] == null ? ApiConsts.sessionID : getSessionId(body['TokenID'] ?? ""); //getSe
          }
          // else  {
          //   body['SessionID'] = body['TokenID'] == null ? ApiConsts.sessionID : getSessionId(body['TokenID'] ?? ""); //getSe
          //
          // }
        }
      }

      //    request.versionID = VERSION_ID;
      //     request.channel = CHANNEL;
      //     request.iPAdress = IP_ADDRESS;
      //     request.generalid = GENERAL_ID;
      //     request.languageID = (languageID == 'ar' ? 1 : 2);
      //     request.patientOutSA = (request.zipCode == '966' || request.zipCode == '+966') ? 0 : 1;

      // body['VersionID'] = ApiConsts.appVersionID.toString();
      if (!isExternal) {
        body['VersionID'] = ApiConsts.appVersionID.toString();
        if (!isRCService) {
          body['Channel'] = ApiConsts.appChannelId.toString();
        }
        body['IPAdress'] = ApiConsts.appIpAddress;
        body['generalid'] = ApiConsts.appGeneralId;

        body['LanguageID'] = _appState.getLanguageID().toString();
        body['Latitude'] = _appState.userLat.toString();
        body['Longitude'] = _appState.userLong.toString();
        body['DeviceTypeID'] = _appState.deviceTypeID;
        if (_appState.appAuthToken.isNotEmpty) {
          body[_appState.isAuthenticated ? 'TokenID' : 'LogInTokenID'] = _appState.appAuthToken;
        }

        // if (url.contains("HMGAI_Lab_Analyze_Orders_API")) {
        //   url = "https://uat.hmgwebservices.com/Services/Patients.svc/REST/HMGAI_Lab_Analyze_Orders_API";
        //   body['TokenID'] = "@dm!n";
        // }
        //
        // if (url.contains("HMGAI_Lab_Analyzer_API")) {
        //   url = "https://uat.hmgwebservices.com/Services/Patients.svc/REST/HMGAI_Lab_Analyzer_API";
        //   body['TokenID'] = "@dm!n";
        // }

        if (url == 'https://uat.hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo') {
          url = "https://hmgwebservices.com/Services/NHIC.svc/REST/GetPatientInfo";
          body['TokenID'] = "@dm!n";
        }

        // body['TokenID'] = "@dm!n";
        // body['PatientID'] = 945786;
        // body['PatientID'] = 53320;
        // body['PatientTypeID'] = 1;
        // body['PatientOutSA'] = 0;
        // body['SessionID'] = "45786230487560q";

        //VIP Patient: 1181868

        // body['IdentificationNo'] = "2235558844";
        // body['MobileNo'] = "966533147722";
        // body['PatientID'] = 809289;
      }

      if (!url.contains("/paymentApi")) {
        body['IsNewFlutterApp'] = true;
      }

      body.removeWhere((key, value) => value == null);
    }

    final bool networkStatus = await Utils.checkConnection(bypassConnectionCheck: bypassConnectionCheck);

    if (!networkStatus) {
      onFailure(
        LocaleKeys.networkPleaseCheckInternet.tr(),
        -1,
        failureType: ConnectivityFailure(LocaleKeys.networkPleaseCheckInternet.tr()),
      );
      _analytics.errorTracking.log("internet_connectivity", error: "no internet available");
      return;
    }

    // Handle body encoding based on isBodyPlainText flag
    final dynamic requestBody = isBodyPlainText ? body : json.encode(body);

    if (kDebugMode) {
      debugPrint("uri: ${Uri.parse(url.trim())}");
      var requestBodyJSON = json.encode(body);
      debugPrint("body: $requestBodyJSON", wrapWidth: 2048);
      // log("body: $requestBodyJSON");
    }

    http.Response response;
    try {
      response = await _httpClient.post(
        uri: Uri.parse(url.trim()),
        body: requestBody,
        headers: headers,
      );
      // log("response: ${response.body.toString()}");
    } on SocketException catch (e) {
      final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
      onFailure(message, -1, failureType: ConnectivityFailure(message));
      _analytics.errorTracking.log(endPoint, error: "SocketException: $e");

      // Enhanced Clarity logging for network errors
      Clarity.setCustomTag('api_err_type', 'socket_exception');
      Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
      Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
      Clarity.setCustomTag('api_err_method', 'POST');
      
      if (_appState.isAuthenticated) {
        Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
      }
      
      Clarity.sendCustomEvent('api_socket_exception');

      return;
    } on http.ClientException catch (e) {
      final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
      onFailure(message, -1, failureType: ConnectivityFailure(message));
      _analytics.errorTracking.log(endPoint, error: "ClientException: $e");
      
      // Enhanced Clarity logging
      Clarity.setCustomTag('api_err_type', 'client_exception');
      Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
      Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
      Clarity.setCustomTag('api_err_method', 'POST');
      
      if (_appState.isAuthenticated) {
        Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
      }
      
      Clarity.sendCustomEvent('api_client_exception');
      
      return;
    } on TimeoutException catch (_) {
      final message = LocaleKeys.networkTimeout.tr();
      onFailure(message, -1, failureType: ConnectivityFailure(message));
      _analytics.errorTracking.log(endPoint, error: "TimeoutException");

      // Enhanced Clarity logging for timeouts
      Clarity.setCustomTag('api_err_type', 'timeout');
      Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
      Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
      Clarity.setCustomTag('api_err_method', 'POST');
      
      if (_appState.isAuthenticated) {
        Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
      }
      
      Clarity.sendCustomEvent('api_timeout');
      
      return;
    } catch (e) {
      final message = LocaleKeys.networkUnknownError.tr();
      onFailure(message, -1, failureType: ConnectivityFailure(message));
      _analytics.errorTracking.log(endPoint, error: "UnknownException: $e");
      
      // Enhanced Clarity logging for unknown errors
      Clarity.setCustomTag('api_err_type', 'unknown_exception');
      Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
      Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
      Clarity.setCustomTag('api_err_method', 'POST');
      
      // Truncate exception message for Clarity
      final exceptionMsg = e.toString();
      final truncatedMsg = exceptionMsg.length > 252 ? '...${exceptionMsg.substring(exceptionMsg.length - 252)}' : exceptionMsg;
      Clarity.setCustomTag('api_err_exception', truncatedMsg);
      
      if (_appState.isAuthenticated) {
        Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
      }
      
      Clarity.sendCustomEvent('api_unknown_exception');
      
      return;
    }

    final int statusCode = response.statusCode;
    // log("response.body: ${response.body}");
    if (statusCode < 200 || statusCode >= 400) {
      onFailure(LocaleKeys.networkErrorWhileFetching.tr(), statusCode, failureType: StatusCodeFailure(LocaleKeys.networkErrorWhileFetching.tr()));
      logApiEndpointError(endPoint, LocaleKeys.networkErrorWhileFetching.tr(), statusCode);

      Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
      // Clarity.setCustomTag('api_err_request', _sanitizeRequestBody(requestBody));
      Clarity.setCustomTag('api_err_status', statusCode.toString());
      Clarity.sendCustomEvent('api_status_code_failure');
    } else {
      var parsed = json.decode(utf8.decode(response.bodyBytes));
      if (isAllowAny) {
        if (isPaymentServices) {
          onSuccess(parsed, statusCode, messageStatus: 1, errorMessage: "");
        } else {
          onSuccess(parsed, statusCode,
              messageStatus: (parsed is Map && parsed.containsKey('MessageStatus')) ? parsed['MessageStatus'] : 1,
              errorMessage: (parsed is Map && parsed.containsKey('ErrorEndUserMessage')) ? parsed['ErrorEndUserMessage'] : "");
        }
      } else {
        if (parsed['Response_Message'] != null) {
          onSuccess(parsed, statusCode,
              messageStatus: (parsed is Map && parsed.containsKey('MessageStatus')) ? parsed['MessageStatus'] : 1,
              errorMessage: (parsed is Map && parsed.containsKey('ErrorEndUserMessage')) ? parsed['ErrorEndUserMessage'] : "");
        } else {
          if (parsed['ErrorType'] == 4) {
            //TODO : handle app update
            // onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode,
            //     failureType: AppUpdateFailure("parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']"));

            ApiClient._navigationService.pushAndRemoveUntil(
                CustomPageRoute(
                    page: AppUpdatePage(
                  appUpdateMessage: parsed['ErrorEndUserMessage'],
                )),
                ModalRoute.withName("/appUpdate"));
            logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
          }
          if (parsed['ErrorType'] == 2) {
            // todo_section: handle Logout
            onFailure(
              parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
              statusCode,
              failureType:
                  UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
            );
            // logApiEndpointError(endPoint, "session logged out", statusCode);
          }
          if (isAllowAny) {
            onSuccess(parsed, statusCode,
                messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
          } else if (parsed['IsAuthenticated'] == null) {
            if (parsed['isSMSSent'] == true) {
              onSuccess(parsed, statusCode,
                  messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
            } else if (parsed['MessageStatus'] == 1) {
              onSuccess(parsed, statusCode,
                  messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
            } else if (parsed['Result'] == 'OK') {
              onSuccess(parsed, statusCode,
                  messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
            } else {
              onFailure(
                parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
                statusCode,
                failureType: MessageStatusFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']),
              );
              logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
            }
          } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) {
            onSuccess(parsed, statusCode,
                messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
          }
          // else if (parsed['IsAuthenticated'] == false) {
          //   onFailure(
          //     "User is not Authenticated",
          //     statusCode,
          //     failureType:
          //         UnAuthenticatedUserFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'] ?? "User is not Authenticated", url: url),
          //   );
          // }
          else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) {
            if (parsed['SameClinicApptList'] != null) {
              onSuccess(parsed, statusCode,
                  messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
            } else {
              if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) {
                if (parsed['ErrorSearchMsg'] == null) {
                  onFailure(
                    LocaleKeys.networkServerErrorNoMessage.tr(),
                    statusCode,
                    failureType: ServerFailure(LocaleKeys.networkErrorWhileFetching.tr()),
                  );
                  logApiEndpointError(endPoint, LocaleKeys.networkServerErrorNoMessage.tr(), statusCode);
                } else {
                  onFailure(
                    parsed['ErrorSearchMsg'],
                    statusCode,
                    failureType: ServerFailure(LocaleKeys.networkErrorWhileFetching.tr()),
                  );
                  logApiEndpointError(endPoint, parsed['ErrorSearchMsg'], statusCode);
                }
              } else {
                onFailure(
                  parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
                  statusCode,
                  failureType: UserIntimationFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']),
                );
                logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode);
              }

              Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
              // Clarity.setCustomTag('api_err_request', _sanitizeRequestBody(requestBody));
              Clarity.setCustomTag('api_err_status', statusCode.toString());
              Clarity.sendCustomEvent('api_message_status_failure');
            }
          } else {
            if (parsed['SameClinicApptList'] != null) {
              onSuccess(parsed, statusCode,
                  messageStatus: parsed['MessageStatus'], errorMessage: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
            } else {
              if (parsed['message'] != null) {
                onFailure(
                  parsed['message'] ?? parsed['message'],
                  statusCode,
                  failureType: ServerFailure(LocaleKeys.networkErrorWhileFetching.tr()),
                );
                logApiEndpointError(endPoint, parsed['message'] ?? parsed['message'], statusCode);
              } else {
                onFailure(
                  parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],
                  statusCode,
                  // failureType: ServerFailure("Error While Fetching data"),
                  failureType: ServerFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']),
                );
                logApiEndpointError(endPoint, parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
              }
            }
          }
        }
      }
    }
    // } catch (e, stackTrace) {
    //   _loggerService.errorLogs(stackTrace.toString());
    //   if (e.toString().contains("ClientException")) {
    //     onFailure('ClientException: Something went wrong, Please try again', -1, failureType: InvalidCredentials('ClientException: Something went wrong, plase try again'));
    //     _analytics.errorTracking.log("internet_connectivity", error: "no internet available");
    //   } else {
    //     onFailure(e.toString(), -1);
    //   }
    //   _analytics.errorTracking.log(endPoint, error: "api exception: $e - API Path: $url");
    // }
  }

  logout() async {
    ApiClient._navigationService.pushAndReplace(AppRoutes.landingScreen);
  }

  @override
  get(String endPoint,
      {required Function(dynamic response, int statusCode) onSuccess,
      required Function(String error, int statusCode) onFailure,
      Map<String, dynamic>? queryParams,
      Map<String, String>? apiHeaders,
      bool isAllowAny = false,
      bool isExternal = false,
      bool isRCService = false}) async {
    String url;
    if (isExternal) {
      url = endPoint;
    } else {
      if (isRCService) {
        url = ApiConsts.rcBaseUrl + endPoint;
      } else {
        url = ApiConsts.baseUrl + endPoint;
      }
    }
    if (queryParams != null) {
      String queryString = Uri(queryParameters: queryParams).query;
      url += '?$queryString';
    }

    debugPrint("URL : $url");
    // print("Body : ${json.encode(body)}");

    if (await Utils.checkConnection(bypassConnectionCheck: true)) {
      http.Response response;
      try {
        response = await _httpClient.get(
          uri: Uri.parse(url.trim()),
          headers: apiHeaders ?? {'Content-Type': 'application/json', 'Accept': 'application/json'},
        );
      } on SocketException catch (e) {
        final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
        onFailure(message, -1);
        _analytics.errorTracking.log(endPoint, error: "SocketException: $e");
        
        // Clarity logging for GET requests
        Clarity.setCustomTag('api_err_type', 'socket_exception');
        Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
        Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
        Clarity.setCustomTag('api_err_method', 'GET');
        
        if (_appState.isAuthenticated) {
          Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
        }
        
        Clarity.sendCustomEvent('api_get_socket_exception');
        
        return;
      } on http.ClientException catch (e) {
        final message = e.message.contains('Connection reset by peer') ? LocaleKeys.networkConnectionReset.tr() : LocaleKeys.networkErrorMessage.tr();
        onFailure(message, -1);
        _analytics.errorTracking.log(endPoint, error: "ClientException: $e");
        
        Clarity.setCustomTag('api_err_type', 'client_exception');
        Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
        Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
        Clarity.setCustomTag('api_err_method', 'GET');
        
        if (_appState.isAuthenticated) {
          Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
        }
        
        Clarity.sendCustomEvent('api_get_client_exception');
        
        return;
      } on TimeoutException catch (_) {
        final message = LocaleKeys.networkTimeout.tr();
        onFailure(message, -1);
        _analytics.errorTracking.log(endPoint, error: "TimeoutException");
        
        Clarity.setCustomTag('api_err_type', 'timeout');
        Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
        Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
        Clarity.setCustomTag('api_err_method', 'GET');
        
        if (_appState.isAuthenticated) {
          Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
        }
        
        Clarity.sendCustomEvent('api_get_timeout');
        
        return;
      } catch (e) {
        final message = LocaleKeys.networkUnknownError.tr();
        onFailure(message, -1);
        _analytics.errorTracking.log(endPoint, error: "UnknownException: $e");
        
        Clarity.setCustomTag('api_err_type', 'unknown_exception');
        Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
        Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
        Clarity.setCustomTag('api_err_method', 'GET');
        
        final exceptionMsg = e.toString();
        final truncatedMsg = exceptionMsg.length > 252 ? '...${exceptionMsg.substring(exceptionMsg.length - 252)}' : exceptionMsg;
        Clarity.setCustomTag('api_err_exception', truncatedMsg);
        
        if (_appState.isAuthenticated) {
          Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
        }
        
        Clarity.sendCustomEvent('api_get_unknown_exception');
        
        return;
      }

      final int statusCode = response.statusCode;
      // print("statusCode :$statusCode");

      if (statusCode < 200 || statusCode >= 400) {
        onFailure(LocaleKeys.networkErrorWhileFetching.tr(), statusCode);
        logApiEndpointError(endPoint, LocaleKeys.networkErrorWhileFetching.tr(), statusCode);
        
        // Clarity logging for GET status code errors
        Clarity.setCustomTag('api_err_type', 'status_code_error');
        Clarity.setCustomTag('api_err_url', _getEndofUrl(url.trim()));
        Clarity.setCustomTag('api_err_endpoint', _getEndpointName(endPoint));
        Clarity.setCustomTag('api_err_method', 'GET');
        Clarity.setCustomTag('api_err_status', statusCode.toString());
        
        if (_appState.isAuthenticated) {
          Clarity.setCustomTag('api_err_user_id', _appState.getAuthenticatedUser()!.patientId.toString());
        }
        
        Clarity.sendCustomEvent('api_get_status_error');
      } else {
        var parsed = json.decode(utf8.decode(response.bodyBytes));
        onSuccess(parsed, statusCode);
      }
    } else {
      onFailure(LocaleKeys.networkPleaseCheckInternet.tr(), -1);
      _analytics.errorTracking.log("internet_connectivity", error: "no internet available");
    }
  }

  // @override
  // simplePost(
  //   String fullUrl, {
  //   required Map<dynamic, dynamic> body,
  //   required Map<String, String> headers,
  //   required Function(dynamic response, int statusCode) onSuccess,
  //   required Function(String error, int statusCode) onFailure,
  // }) async {
  //   String url = fullUrl;
  //   // print("URL Query String: $url");
  //   // print("body: $body");
  //
  //   if (await Utils.checkConnection()) {
  //     headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'});
  //     final response = await http.post(
  //       Uri.parse(url.trim()),
  //       body: json.encode(body),
  //       headers: headers,
  //     );
  //     final int statusCode = response.statusCode;
  //     // print("statusCode :$statusCode");
  //     if (await handleUnauthorized(statusCode, forUrl: fullUrl)) {
  //       simplePost(fullUrl, onFailure: onFailure, onSuccess: onSuccess, body: body, headers: headers);
  //     }
  //
  //     // print(response.body.toString());
  //
  //     if (statusCode < 200 || statusCode >= 400) {
  //       onFailure!('Error While Fetching data', statusCode);
  //       logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode);
  //     } else {
  //       onSuccess!(response.body.toString(), statusCode);
  //     }
  //   } else {
  //     onFailure!('Please Check The Internet Connection', -1);
  //     _analytics.errorTracking.log("internet_connectivity", error: "no internet available");
  //   }
  // }

  // simpleGet(String fullUrl,
  //     {Function(dynamic response, int statusCode)? onSuccess,
  //     Function(String error, int statusCode)? onFailure,
  //     Map<String, dynamic>? queryParams,
  //     Map<String, String>? headers}) async {
  //   headers = headers ?? {};
  //   String url = fullUrl;
  //
  //   var haveParams = (queryParams != null);
  //   if (haveParams) {
  //     String queryString = Uri(queryParameters: queryParams).query;
  //     url += '?$queryString';
  //     // print("URL Query String: $url");
  //   }
  //
  //   if (await Utils.checkConnection()) {
  //     headers.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'});
  //     final response = await http.get(
  //       Uri.parse(url.trim()),
  //       headers: headers,
  //     );
  //
  //     final int statusCode = response.statusCode;
  //     // print("statusCode :$statusCode");
  //     if (await handleUnauthorized(statusCode, forUrl: fullUrl))
  //       simpleGet(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, queryParams: queryParams);
  //
  //     if (statusCode < 200 || statusCode >= 400) {
  //       onFailure!('Error While Fetching data', statusCode);
  //       logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode);
  //     } else {
  //       onSuccess!(response.body.toString(), statusCode);
  //     }
  //   } else {
  //     onFailure!('Please Check The Internet Connection', -1);
  //     _analytics.errorTracking.log("internet_connectivity", error: "no internet available");
  //   }
  // }

  // simplePut(String fullUrl,
  //     {Map<String, dynamic>? body,
  //     Map<String, String>? headers,
  //     Function(dynamic response, int statusCode)? onSuccess,
  //     Function(String error, int statusCode)? onFailure}) async {
  //   String url = fullUrl;
  //   // print("URL Query String: $url");
  //
  //   if (await Utils.checkConnection()) {
  //     headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'});
  //     final response = await http.put(
  //       Uri.parse(url.trim()),
  //       body: json.encode(body),
  //       headers: headers,
  //     );
  //
  //     final int statusCode = response.statusCode;
  //     // print("statusCode :$statusCode");
  //     if (await handleUnauthorized(statusCode, forUrl: fullUrl))
  //       simplePut(fullUrl, onFailure: onFailure, onSuccess: onSuccess, headers: headers, body: body);
  //
  //     if (statusCode < 200 || statusCode >= 400) {
  //       onFailure!('Error While Fetching data', statusCode);
  //       logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode);
  //     } else {
  //       onSuccess!(response.body.toString(), statusCode);
  //     }
  //   } else {
  //     onFailure!('Please Check The Internet Connection', -1);
  //     _analytics.errorTracking.log("internet_connectivity", error: "no internet available");
  //   }
  // }
  //
  // simpleDelete(String fullUrl,
  //     {Function(dynamic response, int statusCode)? onSuccess,
  //     Function(String error, int statusCode)? onFailure,
  //     Map<String, String>? queryParams,
  //     Map<String, String>? headers}) async {
  //   String url = fullUrl;
  //   // print("URL Query String: $url");
  //
  //   var haveParams = (queryParams != null);
  //   if (haveParams) {
  //     String queryString = Uri(queryParameters: queryParams).query;
  //     url += '?$queryString';
  //     // print("URL Query String: $url");
  //   }
  //
  //   if (await Utils.checkConnection()) {
  //     headers!.addAll({'Content-Type': 'application/json', 'Accept': 'application/json'});
  //     final response = await http.delete(
  //       Uri.parse(url.trim()),
  //       headers: headers,
  //     );
  //
  //     final int statusCode = response.statusCode;
  //     // print("statusCode :$statusCode");
  //     if (await handleUnauthorized(statusCode, forUrl: fullUrl))
  //       simpleDelete(fullUrl, onFailure: onFailure, onSuccess: onSuccess, queryParams: queryParams, headers: headers);
  //
  //     if (statusCode < 200 || statusCode >= 400) {
  //       onFailure!('Error While Fetching data', statusCode);
  //       logApiFullUrlError(fullUrl, 'Error While Fetching data', statusCode);
  //     } else {
  //       onSuccess!(response.body.toString(), statusCode);
  //     }
  //   } else {
  //     onFailure!('Please Check The Internet Connection', -1);
  //     _analytics.errorTracking.log("internet_connectivity", error: "no internet available");
  //   }
  // }

  @override
  String getSessionId(String id) {
    return id.replaceAll(RegExp('/[^a-zA-Z]'), '');
  }

  logApiFullUrlError(String fullUrl, error, code) {
    final endpoint = Uri.parse(fullUrl).pathSegments.last;
    logApiEndpointError(endpoint, error, code);
  }

  logApiEndpointError(String endPoint, error, code) {
    _analytics.errorTracking.log(endPoint, error: error);
  }

  String _getEndofUrl(String url) {
    const int clarityLimit = 255;
    if (url.length <= clarityLimit) return url;

    // Extracts the final 252 characters and prepends '...'
    return '...${url.substring(url.length - (clarityLimit - 3))}';
  }

  String _getEndpointName(String endpoint) {
    // Extract the last part of the endpoint path for cleaner tracking
    const int clarityLimit = 100;
    final cleanEndpoint = endpoint.split('/').last;
    
    if (cleanEndpoint.length <= clarityLimit) return cleanEndpoint;
    return '...${cleanEndpoint.substring(cleanEndpoint.length - (clarityLimit - 3))}';
  }

  String _sanitizeRequestBody(String body) {
    if (body.isEmpty) return '';

    try {
      // Handle standard JSON bodies
      final Map<String, dynamic> data = json.decode(body);

      // Case-insensitive key matching and removal
      data.removeWhere((key, value) => key.toLowerCase() == 'sessionid' || key.toLowerCase() == 'tokenid');

      return json.encode(data);
    } catch (_) {
      // Fallback: Handle Form URL Encoded strings or raw key-value pairs (SessionID=XYZ&TokenID=abc)
      String modifiedBody = body;
      final sensitiveKeys = ['SessionID', 'TokenID'];

      for (var key in sensitiveKeys) {
        // Matches "key=value" surrounded by standard query delimiters
        final regExp = RegExp(r'' + key + r'=[^&]*&?', caseSensitive: false);
        modifiedBody = modifiedBody.replaceAll(regExp, '');
      }

      // Clean up any trailing trailing ampersands
      if (modifiedBody.endsWith('&')) {
        modifiedBody = modifiedBody.substring(0, modifiedBody.length - 1);
      }
      return modifiedBody;
    }
  }
}
