import 'package:anyway/data/datasources/trip_local_datasource.dart'; import 'package:anyway/data/datasources/trip_remote_datasource.dart'; import 'package:anyway/domain/entities/landmark.dart'; import 'package:anyway/domain/entities/preferences.dart'; import 'package:anyway/domain/entities/trip.dart'; import 'package:anyway/domain/repositories/trip_repository.dart'; class BackendTripRepository implements TripRepository { final TripRemoteDataSource remote; final TripLocalDataSource local; BackendTripRepository({required this.remote, required this.local}); @override Future getTrip({Preferences? preferences, String? tripUUID, List? landmarks}) async { try { Map json; if (tripUUID != null) { json = await remote.fetchTrip(tripUUID); } else { if (preferences == null) { throw ArgumentError('Either preferences or tripUUID must be provided'); } final Map prefsPayload = _buildPreferencesPayload(preferences); List> landmarkBodies = landmarks != null ? landmarks.map((lm) => lm.toJson()).toList() : await _fetchLandmarkPayloads(prefsPayload, preferences.startLocation); // TODO: remove // restrict the landmark list to 30 to iterate quickly landmarkBodies = landmarkBodies.take(30).toList(); // change the json key because of backend inconsistency for (var lm in landmarkBodies) { if (lm.containsKey('type')) { lm['type'] = "sightseeing"; } lm['osm_type'] = 'node'; lm['osm_id'] = 1; } final Map body = { 'preferences': prefsPayload, 'landmarks': landmarkBodies, 'start': preferences.startLocation, }; if (preferences.endLocation != null) { body['end'] = preferences.endLocation; } if (preferences.detourToleranceMinutes != null) { body['detour_tolerance_minute'] = preferences.detourToleranceMinutes; } json = await remote.createTrip(body); } return Trip.fromJson(json); } catch (e) { throw Exception('Failed to fetch trip: ${e.toString()}'); } } // TODO - maybe shorten this @override Future> searchLandmarks(Preferences preferences) async { final Map prefsPayload = _buildPreferencesPayload(preferences); final List> rawLandmarks = await _fetchLandmarkPayloads(prefsPayload, preferences.startLocation); return rawLandmarks.map((lmJson) => Landmark.fromJson(lmJson)).toList(); } Future>> _fetchLandmarkPayloads( Map prefsPayload, List startLocation) async { final Map landmarkRequest = { 'preferences': prefsPayload, 'start': startLocation, }; return await remote.fetchLandmarks(landmarkRequest); } Map _buildPreferencesPayload(Preferences preferences) { final Map prefsPayload = {}; preferences.scores.forEach((type, score) { prefsPayload[type] = {'type': type, 'score': score}; }); prefsPayload['max_time_minute'] = preferences.maxTimeMinutes; return prefsPayload; } // TODO - should this be moved to a separate local repository? @override Future> getSavedTrips() async { final rawTrips = await local.loadTrips(); return rawTrips.map(Trip.fromJson).toList(growable: false); } @override Future getSavedTrip(String uuid) async { final json = await local.getTrip(uuid); return json == null ? null : Trip.fromJson(json); } @override Future saveTrip(Trip trip) async { await local.upsertTrip(trip.toJson()); } @override Future deleteSavedTrip(String uuid) async { await local.deleteTrip(uuid); } }