import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter_dotenv/flutter_dotenv.dart'; import '../models/trip.dart'; import 'error_service.dart'; /// Service pour géocoder les destinations des voyages class TripGeocodingService { static final TripGeocodingService _instance = TripGeocodingService._internal(); factory TripGeocodingService() => _instance; TripGeocodingService._internal(); final ErrorService _errorService = ErrorService(); static final String _apiKey = dotenv.env['GOOGLE_MAPS_API_KEY'] ?? ''; /// Géocode la destination d'un voyage et retourne un Trip mis à jour Future geocodeTrip(Trip trip) async { try { print('🌍 [TripGeocoding] Géocodage de "${trip.location}"'); // Vérifier si on a déjà des coordonnées récentes if (trip.hasRecentCoordinates) { print('✅ [TripGeocoding] Coordonnées récentes trouvées, pas de géocodage nécessaire'); return trip; } if (_apiKey.isEmpty) { print('❌ [TripGeocoding] Clé API Google Maps manquante'); throw Exception('Clé API Google Maps non configurée'); } final coordinates = await _geocodeDestination(trip.location); if (coordinates != null) { print('✅ [TripGeocoding] Coordonnées trouvées: ${coordinates['lat']}, ${coordinates['lng']}'); return trip.copyWith( latitude: coordinates['lat'], longitude: coordinates['lng'], lastGeocodingUpdate: DateTime.now(), ); } else { print('⚠️ [TripGeocoding] Impossible de géocoder "${trip.location}"'); return trip; } } catch (e) { print('❌ [TripGeocoding] Erreur lors du géocodage: $e'); _errorService.logError('trip_geocoding_service', e); return trip; // Retourner le voyage original en cas d'erreur } } /// Géocode une destination et retourne les coordonnées Future?> _geocodeDestination(String destination) async { try { final url = 'https://maps.googleapis.com/maps/api/geocode/json' '?address=${Uri.encodeComponent(destination)}' '&key=$_apiKey'; print('🌐 [TripGeocoding] URL = $url'); final response = await http.get(Uri.parse(url)); print('📡 [TripGeocoding] Status code = ${response.statusCode}'); if (response.statusCode == 200) { final data = json.decode(response.body); print('📋 [TripGeocoding] Réponse géocodage = ${data['status']}'); if (data['status'] == 'OK' && data['results'].isNotEmpty) { final location = data['results'][0]['geometry']['location']; final coordinates = { 'lat': (location['lat'] as num).toDouble(), 'lng': (location['lng'] as num).toDouble(), }; print('📍 [TripGeocoding] Coordonnées trouvées = $coordinates'); return coordinates; } else { print('⚠️ [TripGeocoding] Erreur API = ${data['error_message'] ?? data['status']}'); return null; } } else { print('❌ [TripGeocoding] Erreur HTTP ${response.statusCode}'); return null; } } catch (e) { print('❌ [TripGeocoding] Exception lors du géocodage: $e'); _errorService.logError('trip_geocoding_service', e); return null; } } /// Vérifie si un voyage a besoin d'être géocodé bool needsGeocoding(Trip trip) { return !trip.hasRecentCoordinates; } /// Géocode plusieurs voyages en batch Future> geocodeTrips(List trips) async { print('🔄 [TripGeocoding] Géocodage de ${trips.length} voyages'); final List geocodedTrips = []; for (final trip in trips) { if (needsGeocoding(trip)) { final geocodedTrip = await geocodeTrip(trip); geocodedTrips.add(geocodedTrip); // Petit délai pour éviter de saturer l'API Google await Future.delayed(const Duration(milliseconds: 200)); } else { geocodedTrips.add(trip); } } print('✅ [TripGeocoding] Géocodage terminé'); return geocodedTrips; } }