import 'package:dio/dio.dart'; import 'package:holzleitner_api/holzleitner_api.dart' as api; import 'package:hl_lieferservice/data/mapper/car_mapper.dart'; import 'package:hl_lieferservice/domain/entity/car.dart'; import 'package:hl_lieferservice/domain/repository/cars_repository.dart'; /// Spricht den generierten Holzleitner-API-Client an und mappt die /// `built_value`-DTOs auf die Domain-Entity. /// /// Fehler aus dem Backend werden in [CarsRepositoryException] /// übersetzt — der Bloc kennt die HTTP-Schicht nicht. 401 fliegt /// ungefangen durch und wird vom übergreifenden /// HolzleitnerAuthInterceptor-Pfad behandelt (Provider-Stream meldet /// `AuthSessionExpired` bei Refresh-Failure). class CarsRepositoryImpl implements CarsRepository { CarsRepositoryImpl(this._api); final api.HolzleitnerApi _api; @override Future> listMine({bool includeInactive = false}) async { try { final response = await _api.getCarsApi().listMyCars( includeInactive: includeInactive, ); final cars = response.data?.cars; if (cars == null) return const []; return cars.toDomainList(); } on DioException catch (e) { throw CarsRepositoryException(_describe(e, 'Laden der Fahrzeuge'), e); } } @override Future create({required String plate}) async { try { final request = api.CreateCarRequest((b) => b..plate = plate); final response = await _api.getCarsApi().createMyCar(createCarRequest: request); final car = response.data?.car; if (car == null) { throw const CarsRepositoryException( 'Server lieferte leere Antwort beim Anlegen', ); } return car.toDomain(); } on DioException catch (e) { throw CarsRepositoryException(_describe(e, 'Anlegen eines Fahrzeugs'), e); } } @override Future update({ required String carId, String? plate, bool? active, }) async { try { final request = api.UpdateCarRequest((b) { if (plate != null) b.plate = plate; if (active != null) b.active = active; }); final response = await _api.getCarsApi().updateMyCar( carId: carId, updateCarRequest: request, ); final car = response.data?.car; if (car == null) { throw const CarsRepositoryException( 'Server lieferte leere Antwort beim Aktualisieren', ); } return car.toDomain(); } on DioException catch (e) { throw CarsRepositoryException( _describe(e, 'Aktualisieren eines Fahrzeugs'), e, ); } } /// Übersetzt eine DioException in eine kompakte, UI-taugliche /// Begründung. Mehr Detail landet im Log, nicht in der Snackbar. String _describe(DioException e, String operation) { final status = e.response?.statusCode; final body = e.response?.data; if (status == 400 && body is Map && body['message'] != null) { return '$operation fehlgeschlagen: ${body['message']}'; } if (status == 401) return 'Sitzung abgelaufen'; if (status == 404) return 'Fahrzeug nicht gefunden'; return '$operation fehlgeschlagen (HTTP ${status ?? 'unbekannt'})'; } }