import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:wanisdriver/Provider/utils_singleton.dart'; import 'package:intl/intl.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../config/api_response.dart'; import 'package:http/http.dart' as http; import '../config/constants/app_constant.dart'; import '../config/constants/consts.dart'; import '../models/DriverLocationDto.dart'; import '../models/DriverSummary.dart'; import '../models/users.dart'; class driverservice{ String token = ''; int statusCode = -1; bool errorToken = false; static final Map>> _locationCache = {}; Future getToken() async { final prefs = await SharedPreferences.getInstance(); if (prefs.getString('token') == null || prefs.getString('token') == '') { prefs.setString('token', 'InvalidToken'); } if (prefs.getString('token') != null) { token = prefs.getString('token')!; } return token.toString(); } Future> updateVehicleImages({ File? carteGrise, File? insurance, List? carImages, List? permisImages, List? cinImages, int? vehicleYear, String? plateNumber, String? cin, String? phone, String? name, }) async { print("🚗 updateVehicleImages started"); errorToken = false; statusCode = -1; await getToken(); try { var uri = Uri.https(url, '/api/v1/driver/add_image_vehicle'); var request = http.MultipartRequest('POST', uri); // Add headers request.headers.addAll({ 'Authorization': 'Bearer $token', 'Accept': 'application/json', }); // Add carte grise image if (carteGrise != null) { request.files.add( await http.MultipartFile.fromPath( 'categris', carteGrise.path, ), ); print("✅ Added carte grise"); } // Add insurance image if (insurance != null) { request.files.add( await http.MultipartFile.fromPath( 'insurance', insurance.path, ), ); print("✅ Added insurance"); } // Add car images if (carImages != null && carImages.isNotEmpty) { for (var carImage in carImages) { request.files.add( await http.MultipartFile.fromPath( 'carimages', carImage.path, ), ); } print("✅ Added ${carImages.length} car images"); } if (cinImages != null && cinImages.isNotEmpty) { for (var cinImage in cinImages) { request.files.add( await http.MultipartFile.fromPath( 'cin', cinImage.path, ), ); } print("✅ Added ${cinImages.length} cin images"); } if (permisImages != null && permisImages.isNotEmpty) { for (var permisImage in permisImages) { request.files.add( await http.MultipartFile.fromPath( 'permis', permisImage.path, ), ); } print("✅ Added ${permisImages.length} permis images"); } // Add vehicle year if (vehicleYear != null) { request.fields['vehicleyear'] = vehicleYear.toString(); print("✅ Added vehicle year: $vehicleYear"); } if (name != null) { request.fields['name'] = name.toString(); print("✅ Added name: $name"); } if (phone != null) { request.fields['phonenumber'] = phone.toString(); print("✅ Added phone: $phone"); } if (cin != null) { request.fields['cinnumber'] = cin.toString(); print("✅ Added cin: $cin"); } // Add plate number if (plateNumber != null && plateNumber.isNotEmpty) { request.fields['platenumber'] = plateNumber; print("✅ Added plate number: $plateNumber"); } print("📤 Sending request..."); var streamedResponse = await request.send(); var response = await http.Response.fromStream(streamedResponse); statusCode = response.statusCode; print("📥 Response status code: $statusCode"); if (response.statusCode == 200 || response.statusCode == 201) { print("🟢 Success - Status code: ${response.statusCode}"); final jsonData = json.decode(response.body); users profile = users.fromJson(jsonData); print("🟡 Updated profile: ${profile.driver?.vehicle?.vehicleModel}"); return APIResponse(statusCode: statusCode, data: profile); } print("🔴 Error response: ${response.body}"); Future.microtask(() async => await logError( errorCode: statusCode.toString(), errorMessage: response.body, path: '/api/v1/driver/add_image_vehicle')); return APIResponse( statusCode: statusCode, errorMessage: 'Failed to update vehicle images'); } catch (err, stacktrace) { print("🔴 updateVehicleImages Error: $err"); log(err.toString()); Future.microtask(() async => await logError( errorCode: statusCode.toString(), errorMessage: "Caught error: $err", path: '/api/v1/driver/add_image_vehicle')); print("Stacktrace: $stacktrace"); return APIResponse( statusCode: statusCode, errorMessage: 'No internet connection', ); } } Future> updateavailabilty() async { print("🟢🟣🟢🟣 updateavailabilty 🟢🟣🟢🟣 --- ****** / ************** --- ${utils.user!.driver!.available}" ); errorToken = false; statusCode = -1; await getToken(); return await http.patch( Uri.https(url, '/api/v1/driver/update_availability'), headers: { 'Authorization': 'Bearer $token', 'Content-type': 'application/json', 'Accept': 'application/json' }, ).then((data) async { statusCode = data.statusCode; if (data.statusCode == 200 || data.statusCode == 201) { print("🟢🟣 data.statusCode --- 200 / 201 --- " ); // final codeUnits = data.body.codeUnits; // var str = const Utf8Decoder().convert(codeUnits); final jsonData = json.decode(data.body); users profile = users.fromJson(jsonData); print("🟡 🟡 profile : $profile"); return APIResponse(statusCode: statusCode, data: profile); } Future.microtask(() async => await logError( errorCode: statusCode.toString(), errorMessage: data.body, path: '/api/v1/driver/update_availability')); return APIResponse( statusCode: statusCode, errorMessage: 'Please check your info'); }).catchError((err, stacktrace) { print("-------> update availability Error :"); log(err.toString()); Future.microtask(() async => await logError( errorCode: statusCode.toString(), errorMessage: "Caught error : $err", path: '/api/v1/driver/update_availability')); print("acktrace : $stacktrace"); return APIResponse( statusCode: statusCode, errorMessage: 'no internet connection', ); }); } Future> finddriverlocationby(int driverid) async { // Check if there's already an ongoing request for this driver if (_locationCache.containsKey(driverid)) { print('→ waiting for existing request for driver #$driverid'); return await _locationCache[driverid]!; } print('→ about to fetch ride #$driverid from: https://$url/api/v1/driver/driver_current_location/$driverid'); // Create the future and cache it immediately final future = _performLocationRequest(driverid); _locationCache[driverid] = future; // Wait for completion and clean up cache final result = await future; _locationCache.remove(driverid); return result; } Future> _performLocationRequest(int driverid) async { 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()); } } // Optional: Method to clear cache if needed static void clearLocationCache() { _locationCache.clear(); } // Optional: Method to clear specific driver from cache static void clearDriverFromCache(int driverid) { _locationCache.remove(driverid); } Future> updateavailabiltyalwaysonline() async { print("🟢🟣🟢🟣 updateavailabilty 🟢🟣🟢🟣 --- ****** / ************** --- ${utils.user!.driver!.available}" ); errorToken = false; statusCode = -1; await getToken(); return await http.patch( Uri.https(url, '/api/v1/driver/update_availability_always_online'), headers: { 'Authorization': 'Bearer $token', 'Content-type': 'application/json', 'Accept': 'application/json' }, ).then((data) async { statusCode = data.statusCode; if (data.statusCode == 200 || data.statusCode == 201) { print("🟢🟣 data.statusCode --- 200 / 201 --- " ); // final codeUnits = data.body.codeUnits; // var str = const Utf8Decoder().convert(codeUnits); final jsonData = json.decode(data.body); users profile = users.fromJson(jsonData); print("🟡 🟡 profile : $profile"); return APIResponse(statusCode: statusCode, data: profile); } Future.microtask(() async => await logError( errorCode: statusCode.toString(), errorMessage: data.body, path: '/api/v1/driver/update_availability')); return APIResponse( statusCode: statusCode, errorMessage: 'Please check your info'); }).catchError((err, stacktrace) { print("-------> update availability Error :"); log(err.toString()); Future.microtask(() async => await logError( errorCode: statusCode.toString(), errorMessage: "Caught error : $err", path: '/api/v1/driver/update_availability')); print("acktrace : $stacktrace"); return APIResponse( statusCode: statusCode, errorMessage: 'no internet connection', ); }); } Future> getdriversummury(DateTime date) async { errorToken = false; statusCode = -1; await getToken(); // Format DateTime to a valid query string format (e.g., yyyy-MM-dd) final Map query = { "date": DateFormat('yyyy-MM-dd').format(date), // Format date as string }; return await http.get( Uri.https(url, '/api/v1/driver/driver-sessions/summary', query), headers: { 'Authorization': 'Bearer $token', 'Content-type': 'application/json', 'Accept': 'application/json' }, ).then((data) async { statusCode = data.statusCode; if (data.statusCode == 200 || data.statusCode == 201) { // final codeUnits = data.body.codeUnits; // var str = const Utf8Decoder().convert(codeUnits); final jsonData = json.decode(data.body); DriverSummary profile = DriverSummary.fromJson(jsonData); return APIResponse(statusCode: statusCode, data: profile); } Future.microtask(() async => await logError( errorCode: statusCode.toString(), errorMessage: data.body, path: '/api/v1/driver/driver-sessions/summary')); return APIResponse( statusCode: statusCode, errorMessage: 'Please check your info'); }).catchError((err, stacktrace) { print("-------> summary Error :"); log(err.toString()); Future.microtask(() async => await logError( errorCode: statusCode.toString(), errorMessage: "Caught error : $err", path: '/api/v1/driver/driver-sessions/summary')); print("acktrace : $stacktrace"); return APIResponse( statusCode: statusCode, errorMessage: 'no internet connection', ); }); } Future logError( {String? comment, required String errorCode, required String errorMessage, required String path}) async { errorToken = false; statusCode = -1; await getToken(); final Map query = { "clientid": "283386", "comment": comment ?? "No comment provided", "errorcode": errorCode, "errormessage": errorMessage, "path": path, "source": "MOBILE_APP", "useremail": utils.user?.email ?? "email@email.com", // [email@email.com] this email is for user not logged in "username": utils.user?.name ?? "anonymous user", "userphonenumber": utils.user?.phoneNumber ?? "00000000", }; return await http.post( Uri.https(AppString.reportLink, 'api/v1/servererror/new_error', query), headers: { 'Content-type': 'application/json', 'Accept': 'application/json' }, ).then((data) async { statusCode = data.statusCode; if (data.statusCode == 200 || data.statusCode == 201) { return APIResponse(statusCode: statusCode); } return APIResponse( statusCode: statusCode, errorMessage: 'Please check your info'); }).catchError((_) { return APIResponse( statusCode: statusCode, errorMessage: 'no internet connection'); }); } }