143 lines
4.5 KiB
Dart
143 lines
4.5 KiB
Dart
import 'dart:convert';
|
|
import 'dart:developer';
|
|
|
|
import 'package:dio/dio.dart';
|
|
|
|
abstract class TripRemoteDataSource {
|
|
/// Fetch available landmarks for the provided preferences/start payload.
|
|
Future<List<Map<String, dynamic>>> fetchLandmarks(Map<String, dynamic> body);
|
|
|
|
/// Create a new trip using the optimizer payload (that includes landmarks).
|
|
Future<Map<String, dynamic>> createTrip(Map<String, dynamic> body);
|
|
|
|
/// Fetch an existing trip by UUID
|
|
Future<Map<String, dynamic>> fetchTrip(String uuid);
|
|
}
|
|
|
|
class TripRemoteDataSourceImpl implements TripRemoteDataSource {
|
|
final Dio dio;
|
|
|
|
TripRemoteDataSourceImpl({required this.dio});
|
|
|
|
@override
|
|
Future<List<Map<String, dynamic>>> fetchLandmarks(Map<String, dynamic> body) async {
|
|
final response = await dio.post('/get/landmarks', data: body);
|
|
if (response.statusCode != 200) {
|
|
throw Exception('Server error fetching landmarks: ${response.statusCode}');
|
|
}
|
|
|
|
if (response.data is! List) {
|
|
throw Exception('Unexpected landmarks response format');
|
|
}
|
|
|
|
return _normalizeLandmarks(List<dynamic>.from(response.data as List));
|
|
}
|
|
|
|
@override
|
|
Future<Map<String, dynamic>> createTrip(Map<String, dynamic> body) async {
|
|
log('Creating trip with body: $body');
|
|
// convert body to actual json
|
|
String bodyJson = jsonEncode(body);
|
|
log('Trip request JSON: $bodyJson');
|
|
final response = await dio.post('/optimize/trip', data: body);
|
|
if (response.statusCode != 200) {
|
|
throw Exception('Server error: ${response.statusCode}');
|
|
}
|
|
|
|
if (response.data is! Map<String, dynamic>) {
|
|
throw Exception('Unexpected response format');
|
|
}
|
|
|
|
final Map<String, dynamic> json = Map<String, dynamic>.from(response.data as Map);
|
|
|
|
_ensureLandmarks(json);
|
|
if (json.containsKey('landmarks') && json['landmarks'] is List) {
|
|
return json;
|
|
}
|
|
|
|
final String? firstUuid = json['first_landmark_uuid'] as String?;
|
|
if (firstUuid == null) {
|
|
return json;
|
|
}
|
|
|
|
final List<Map<String, dynamic>> landmarks = [];
|
|
String? next = firstUuid;
|
|
while (next != null) {
|
|
final lm = await _fetchLandmarkByUuid(next);
|
|
landmarks.add(lm);
|
|
final dynamic nxt = lm['next_uuid'];
|
|
next = (nxt is String) ? nxt : null;
|
|
}
|
|
|
|
json['landmarks'] = landmarks;
|
|
return json;
|
|
}
|
|
|
|
@override
|
|
Future<Map<String, dynamic>> fetchTrip(String uuid) async {
|
|
final response = await dio.get('/trip/$uuid');
|
|
if (response.statusCode != 200) {
|
|
throw Exception('Server error: ${response.statusCode}');
|
|
}
|
|
if (response.data is! Map<String, dynamic>) {
|
|
throw Exception('Unexpected response format');
|
|
}
|
|
|
|
final Map<String, dynamic> json = Map<String, dynamic>.from(response.data as Map);
|
|
// Normalize same as createTrip: if trip contains first_landmark_uuid, expand chain
|
|
if (json.containsKey('landmarks') && json['landmarks'] is List) {
|
|
_ensureLandmarks(json);
|
|
return json;
|
|
}
|
|
|
|
final String? firstUuid = json['first_landmark_uuid'] as String?;
|
|
if (firstUuid == null) return json;
|
|
|
|
final List<Map<String, dynamic>> landmarks = [];
|
|
String? next = firstUuid;
|
|
while (next != null) {
|
|
final lm = await _fetchLandmarkByUuid(next);
|
|
landmarks.add(lm);
|
|
final dynamic nxt = lm['next_uuid'];
|
|
next = (nxt is String) ? nxt : null;
|
|
}
|
|
|
|
json['landmarks'] = landmarks;
|
|
return json;
|
|
}
|
|
|
|
// Fetch a single landmark by uuid via the /landmark/{landmark_uuid} endpoint
|
|
Future<Map<String, dynamic>> _fetchLandmarkByUuid(String uuid) async {
|
|
final response = await dio.get('/landmark/$uuid');
|
|
if (response.statusCode != 200) {
|
|
throw Exception('Failed to fetch landmark $uuid: ${response.statusCode}');
|
|
}
|
|
if (response.data is! Map<String, dynamic>) {
|
|
throw Exception('Unexpected landmark response format');
|
|
}
|
|
return _normalizeLandmark(Map<String, dynamic>.from(response.data as Map));
|
|
}
|
|
|
|
static void _ensureLandmarks(Map<String, dynamic> json) {
|
|
final raw = json['landmarks'];
|
|
if (raw is List) {
|
|
json['landmarks'] = _normalizeLandmarks(raw);
|
|
}
|
|
}
|
|
|
|
static List<Map<String, dynamic>> _normalizeLandmarks(List<dynamic> rawList) {
|
|
return rawList
|
|
.map((item) => _normalizeLandmark(Map<String, dynamic>.from(item as Map)))
|
|
.toList();
|
|
}
|
|
|
|
static Map<String, dynamic> _normalizeLandmark(Map<String, dynamic> source) {
|
|
final normalized = Map<String, dynamic>.from(source);
|
|
final typeValue = normalized['type'];
|
|
if (typeValue is String) {
|
|
normalized['type'] = {'type': typeValue};
|
|
}
|
|
return normalized;
|
|
}
|
|
}
|