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/data/network/api_failure_text.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; // Eine leere Antwort ist ein Fehler, nicht „keine Fahrzeuge". if (cars == null) { throw const CarsRepositoryException( 'Fahrzeuge konnten nicht geladen werden. Bitte erneut versuchen', ); } 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) => describeApiFailure( e, operation: operation, byStatus: const {404: 'Fahrzeug nicht gefunden'}, byServerText: const { 'existiert bereits': 'Dieses Kennzeichen ist bereits vergeben', 'plate darf nicht leer': 'Bitte ein Kennzeichen eingeben', }, ); }