import 'dart:convert'; import 'dart:developer'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import '../config/api_response.dart'; import '../config/constants/app_constant.dart'; import '../models/DriverLocationDto.dart'; import '../models/RideUpdateRequest.dart'; import '../models/SocketRequest/ride_request.dart'; import '../models/ride_model.dart'; import '../providers/utils_singleton.dart'; class RideService { int statusCode = -1; bool errorToken = false; static final Map>> _rideCache = {}; static final Map>> _rideStatusCache = {}; Future> fetchbyid(int rideId) async { // Check if there's already an ongoing request for this ride ID if (_rideCache.containsKey(rideId)) { print('→ waiting for existing request for ride #$rideId'); return await _rideCache[rideId]!; } print('→ about to fetch ride #$rideId from: https://$url/api/ride/ride/$rideId'); // Create the future and cache it immediately final future = _performFetchById(rideId); _rideCache[rideId] = future; // Wait for completion and clean up cache final result = await future; _rideCache.remove(rideId); return result; } Future> _performFetchById(int rideId) async { try { // Ensure token is fetched before making the request var uri = Uri.https(url, '/api/ride/ride/$rideId'); // Make the GET request final response = await http.get( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); print('status code : ${response.statusCode}'); print('status body : ${response.body}'); if (response.statusCode == 200 || response.statusCode == 201) { // Decode the JSON response final data = json.decode(response.body); // Process the user data return APIResponse(statusCode: response.statusCode, data: RideDto.fromJson(data)); } else { log('Failed to load user data. Status code: ${response.statusCode}'); return APIResponse(statusCode: response.statusCode, errorMessage: 'Failed to load user data. Status code: ${response.statusCode}'); } } catch (e) { log('Error occurred 04: $e'); return APIResponse(errorMessage: e.toString()); } } // Optional: Methods to clear cache if needed static void clearRideCache() { _rideCache.clear(); _rideStatusCache.clear(); } // Optional: Method to clear specific ride from cache static void clearRideFromCache(int rideId) { _rideCache.remove(rideId); } // Optional: Method to clear specific status from cache static void clearStatusFromCache(String status) { _rideStatusCache.remove(status); } Future> finddriverlocationby(int driverid) async { print( '→ about to fetch ride #$driverid from: https://$url/api/v1/driver/driver_current_location/$driverid'); try { var uri = Uri.https(url, '/api/v1/driver/driver_current_location/$driverid'); // Make the GET request final response = await http.get( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); print('status code : ${response.statusCode}'); print('status body : ${response.body}'); if (response.statusCode == 200 || response.statusCode == 201) { // Decode the JSON response final data = json.decode(response.body); DriverLocationDto location = DriverLocationDto.fromJson(data); // Process the user data log("location : ${location.toString()}"); log("data : ${data.toString()}"); return APIResponse(statusCode: response.statusCode, data: location); } else { log('Failed to load location data. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load location data. Status code: ${response.statusCode}'); } } catch (e) { log('Error occurred 02: $e'); return APIResponse(errorMessage: e.toString()); } } Future> send_update_ride(RideUpdateRequest request) async { print( '→ about to fetch ride ----#${request.rideId} ** ${request.message} ** ${request.riderusername} from: https://$url/api/ride/update_ride/'); try { // Ensure token is fetched before making the request var uri = Uri.https(url, '/api/ride/update_ride'); // Make the GET request final response = await http.post( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: jsonEncode(request.toJson()), ); print('status code send_update_ride : ${response.statusCode}'); print('status body send_update_ride : ${response.body}'); if (response.statusCode == 200 || response.statusCode == 201) { return APIResponse(statusCode: response.statusCode, data: true); } else { log('Failed to load user data. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load user data. Status code: ${response.statusCode}', data: false); } } catch (e) { log('Error occurred 03: $e'); return APIResponse(errorMessage: e.toString(), data: false); } } Future> RideCancelbyuser(int rideId) async { print( '→ about to cancel ride #$rideId from: https://$url/api/ride/user_cancel_ride/$rideId'); try { var uri = Uri.https(url, '/api/ride/user_cancel_ride/$rideId'); // Make the GET request final response = await http.put( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); print('status code : ${response.statusCode}'); print('status body : ${response.body}'); if (response.statusCode == 200 || response.statusCode == 201) { return APIResponse(statusCode: response.statusCode, data: true); } else { log('Failed to load user data. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, data: false, errorMessage: 'Failed to load user data. Status code: ${response.statusCode}'); } } catch (e) { log('Error occurred 03: $e'); return APIResponse(errorMessage: e.toString(), data: false); } } Future> get_my_latest_ride_not_rated() async { print( '→ about to fetch ride # from: https://$url/api/ride/get_my_latest_not_rated_ride'); try { var uri = Uri.https(url, '/api/ride/get_my_latest_not_rated_ride'); final response = await http.get( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); print('status code : ${response.statusCode}'); print( 'status body : "${response.body}"'); // quotes help catch whitespace-only responses // Handle success (200/201) if (response.statusCode == 200 || response.statusCode == 201) { final trimmedBody = response.body.trim(); if (trimmedBody.isNotEmpty) { try { final data = json.decode(trimmedBody); final ride = RideDto.fromJson(data); log("✅ ride: $ride"); return APIResponse(statusCode: response.statusCode, data: ride); } catch (jsonError) { log('❌ JSON decoding failed: $jsonError'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Invalid JSON format from server.', ); } } else { log("ℹ️ Empty response body received. No unrated ride found."); return APIResponse( statusCode: response.statusCode, errorMessage: 'No unrated ride found.', data: null, ); } } else { // Non-success HTTP status log('❌ Failed to load ride. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load ride. Status code: ${response.statusCode}', ); } } catch (e) { // Network error, timeout, etc. log('❗ Error occurred while fetching unrated ride: $e'); return APIResponse(errorMessage: e.toString()); } } Future> get_my_latest_ride_by_status( String status) async { print( '→ about to fetch ride #$status from: https://$url/api/ride/get_my_latest_ride_by_status?status=$status'); try { var uri = Uri.https( url, '/api/ride/get_my_latest_ride_by_status', {'status': status}); final response = await http.get( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); print('status code : ${response.statusCode}'); print( 'status body : "${response.body}"'); // Wrap in quotes to see empty strings if (response.statusCode == 200 || response.statusCode == 201) { // Check if body is not empty or just whitespace if (response.body.trim().isNotEmpty) { try { final data = json.decode(response.body); RideDto ride = RideDto.fromJson(data); log("ride : ${ride.toString()}"); log("data : ${data.toString()}"); return APIResponse(statusCode: response.statusCode, data: ride); } catch (jsonError) { log('JSON decode error: $jsonError'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Invalid JSON format in response.', ); } } else { // Empty response body is valid, just no data log('Empty response body received.'); return APIResponse(statusCode: response.statusCode, data: null); } } else { log('Failed to load ride data. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load ride data. Status code: ${response.statusCode}', ); } } catch (e) { log('Error occurred 0: $e'); return APIResponse(errorMessage: e.toString()); } } Future> get_my_latest_ride() async { print( '→ about to fetch ride #0 from: https://$url/api/ride/get_my_latest_ride_by_status'); try { var uri = Uri.https(url, '/api/ride/get_my_latest_ride_by_status'); final response = await http.get( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); print('status code : ${response.statusCode}'); print( 'status body : "${response.body}"'); // Wrap in quotes to see empty strings if (response.statusCode == 200 || response.statusCode == 201) { // Check if body is not empty or just whitespace if (response.body.trim().isNotEmpty) { try { final data = json.decode(response.body); RideDto ride = RideDto.fromJson(data); log("ride : ${ride.toString()}"); log("data : ${data.toString()}"); return APIResponse(statusCode: response.statusCode, data: ride); } catch (jsonError) { log('JSON decode error: $jsonError'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Invalid JSON format in response.', ); } } else { // Empty response body is valid, just no data log('Empty response body received.'); return APIResponse(statusCode: response.statusCode, data: null); } } else { log('Failed to load ride data. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load ride data. Status code: ${response.statusCode}', ); } } catch (e) { log('Error occurred 0: $e'); return APIResponse(errorMessage: e.toString()); } } Future> get_nbDriver(int ride_id) async { print( '→ about to fetch ride #0 from: https://$url/api/v1/logs/driver_assigned_count/{ride_id}'); try { var uri = Uri.https(url, '/api/v1/logs/driver_assigned_count/${ride_id}'); final response = await http.get( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, ); print('status code : ${response.statusCode}'); print( 'status body : "${response.body}"'); // Wrap in quotes to see empty strings if (response.statusCode == 200 || response.statusCode == 201) { // Check if body is not empty or just whitespace if (response.body.trim().isNotEmpty) { try { return APIResponse(statusCode: response.statusCode, data: int.tryParse(response.body) ?? -1); } catch (jsonError) { log('JSON decode error: $jsonError'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Invalid JSON format in response.', ); } } else { // Empty response body is valid, just no data log('Empty response body received.'); return APIResponse(statusCode: response.statusCode, data: null); } } else { log('Failed to load ride data. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load ride data. Status code: ${response.statusCode}', ); } } catch (e) { log('Error occurred 0: $e'); return APIResponse(errorMessage: e.toString()); } } Future> createride(RideRequestModel request) async { try { log('/api/ride/user-create'); var uri = Uri.https(url, '/api/ride/user-create'); final response = await http.post( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: jsonEncode(request), ); if (response.statusCode == 200 || response.statusCode == 201) { // Decode the JSON response final data = json.decode(response.body); RideDto ride = RideDto.fromJson(data); // Process the user data log("ride : ${ride.toString()}"); log("data : ${data.toString()}"); return APIResponse(statusCode: response.statusCode, data: ride); } else { log('Failed to load user data. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load user data. Status code: ${response.statusCode}'); } } catch (e) { return APIResponse(errorMessage: e.toString()); } } Future> updateride( int rideId, String cancelreason, String type) async { try { var uri = Uri.https(url, '/api/ride/update-ride'); final payload = jsonEncode({ 'rideId': rideId, "type": type, "message": cancelreason, }); final response = await http.post( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: payload, ); if (response.statusCode == 200 || response.statusCode == 201) { // Decode the JSON response final data = json.decode(response.body); RideDto ride = RideDto.fromJson(data); // Process the user data log("ride : ${ride.toString()}"); log("data : ${data.toString()}"); return APIResponse(statusCode: response.statusCode, data: ride); } else { log('Failed to load user data. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load user data. Status code: ${response.statusCode}'); } } catch (e) { return APIResponse(errorMessage: e.toString()); } } Future rate_driver(int rating, int driverid) async { try { var uri = Uri.https( url, '/api/v1/rating/rate_driver/$driverid', {'rate': rating.toString()}, ); // Make the GET request final response = await http.post( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Accept': 'application/json', }, ); print('status code : ${response.statusCode}'); print('status body : ${response.body}'); if (response.statusCode == 200 || response.statusCode == 201) { return APIResponse(statusCode: response.statusCode, data: true); } else { log('Failed to load user data. Status code: ${response.statusCode}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load user data. Status code: ${response.statusCode}'); } } catch (e) { log('Error occurred 06: $e'); return APIResponse(errorMessage: e.toString()); } } Future>> fetchRides({int? page, int? size, String? type,String? status}) async { try { print("Token ${utils.token}"); var uri; if(status!=null){ uri = Uri.https(url, '/api/ride/all_my_rides', { 'page': page.toString(), 'size': size.toString(), 'type': type, 'status': status, }); }else{ uri = Uri.https(url, '/api/ride/all_my_rides', { 'page': page.toString(), 'size': size.toString(), 'type': type, });} final response = await http.get( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Accept': 'application/json', }, ); log("Response status: ${response.statusCode}"); log("Response body: ${response.body}"); if (response.statusCode == 200) { final data = json.decode(response.body); print("----------data------------$data"); List rides = []; try { final List resultList = data['result']; for (var item in resultList) { try { final ride = RideDto.fromJson(item); rides.add(ride); } catch (e, st) { print("RideDto parse error: $e"); print("Item causing error: $item"); } } } catch (e, st) { print("Outer parse error: $e"); } print("----------rides------------$rides"); return APIResponse(statusCode: response.statusCode, data: rides); } else { return APIResponse( statusCode: response.statusCode, errorMessage: 'Error ${response.statusCode}', ); } } catch (e) { return APIResponse(errorMessage: e.toString()); } } Future>> fetchRidesStatus({int? page, int? size, String? type,bool? history, required List status}) async { try { print("Token ${utils.token}"); print("status $status"); print("history --------------------------------------------------- $history"); // Create a mutable map for query parameters final Map queryParams = { 'page': page?.toString(), 'size': size?.toString(), 'type': type, 'status': status, }; // Conditionally add the 'history' parameter if (history != null) { queryParams['history'] = history.toString(); } var uri = Uri.https(url, '/api/ride/all_my_rides_by_status', queryParams); print("uri --------------------------------------------------- $uri"); final response = await http.get( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Accept': 'application/json', }, ); log("Response status: ${response.statusCode}"); log("Response body: ${response.body}"); if (response.statusCode == 200) { final data = json.decode(response.body); print("----------data------------$data"); List rides = []; try { final List resultList = data['result']; for (var item in resultList) { try { final ride = RideDto.fromJson(item); rides.add(ride); } catch (e, st) { print("RideDto parse error: $e"); print("Item causing error: $item"); } } } catch (e, st) { print("Outer parse error: $e"); } print("----------rides------------$rides"); return APIResponse(statusCode: response.statusCode, data: rides); } else { return APIResponse( statusCode: response.statusCode, errorMessage: 'Error ${response.statusCode}', ); } } catch (e) { return APIResponse(errorMessage: e.toString()); } } Future postRideScheduledData( Map metadata) async { var uri = Uri.https(url, '/api/ride/user_schedule_ride_create'); // Make the GET request final response = await http.post( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: jsonEncode(metadata), ); log("response data : ' **** ${response.body}"); log("response data : ' **** ${response.statusCode}"); return response; } Future updateRideScheduledData( Map metadata, idRide) async { var uri = Uri.https(url, '/api/ride/update_user_schedule_ride/$idRide'); // Make the GET request final response = await http.patch( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: jsonEncode(metadata), ); return response; } Future CancelRideScheduled(int idRide) async { var uri = Uri.https(url, '/api/ride/update_user_schedule_ride/$idRide'); // Make the GET request final response = await http.patch( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: jsonEncode({"rideStatus": "CANCELLED"}), ); return response; } Future> request_ride(RideRequestModel request) async { print('→ about to fetch ride #${request.uuid} from: https://$url/api/ride/request_ride_user/'); try { log("request ride body send : ${jsonEncode(request.toJson())}"); // Ensure token is fetched before making the request var uri = Uri.https(url, '/api/ride/request_ride_user'); // Make the GET request final response = await http.post( uri, headers: { 'Authorization': 'Bearer ${utils.token}', 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: jsonEncode(request.toJson()), ); print('request_ride status code : ${response.statusCode}'); print('request_ride status body : ${response.body}'); if (response.statusCode == 200 || response.statusCode == 201) { return APIResponse(statusCode: response.statusCode, data: true); } else { log('Failed to load user data. Status code: ${response.statusCode}'); log('Failed to load user data. Status code: ${response.body}'); return APIResponse( statusCode: response.statusCode, errorMessage: 'Failed to load user data. Status code: ${response.statusCode}', data: false); } } catch (e) { log('Error occurred 07: $e'); return APIResponse(errorMessage: e.toString(), data: false); } } }