import 'package:flutter_bloc/flutter_bloc.dart';

import 'package:hl_lieferservice/domain/entity/car.dart';
import 'package:hl_lieferservice/domain/repository/cars_repository.dart';
import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart';
import 'package:hl_lieferservice/widget/operations/bloc/operation_event.dart';

import 'cars_event.dart';
import 'cars_state.dart';

/// Bloc für die Fahrzeugverwaltung des angemeldeten Fahrers.
///
/// `personalnummer`/`teamId` wird **nicht mehr** in den Events
/// übergeben — der Account kommt serverseitig aus dem JWT.
/// Session-Expiry geht über den globalen Provider-Stream
/// (KeycloakOidcTokenProvider → AuthSessionExpired), nicht über
/// dieses Bloc.
class CarsBloc extends Bloc<CarEvents, CarsState> {
  CarsBloc({required this.repository, required this.opBloc})
    : super(const CarsInitial()) {
    on<CarLoad>(_handleLoad);
    on<CarAdd>(_handleAdd);
    on<CarEdit>(_handleEdit);
    on<CarDeactivate>(_handleDeactivate);
  }

  final CarsRepository repository;
  final OperationBloc opBloc;

  Future<void> _handleLoad(CarLoad event, Emitter<CarsState> emit) async {
    if (state is CarsLoaded && !event.force) return;

    emit(const CarsLoading());
    try {
      final cars = await repository.listMine();
      emit(CarsLoaded(cars: cars));
    } on CarsRepositoryException catch (e) {
      emit(CarsLoadingFailed(message: e.message));
    } catch (_) {
      emit(const CarsLoadingFailed());
    }
  }

  Future<void> _handleAdd(CarAdd event, Emitter<CarsState> emit) async {
    final current = state;
    opBloc.add(StartOperation());
    try {
      final created = await repository.create(plate: event.plate);
      if (current is CarsLoaded) {
        emit(current.copyWith(cars: [...current.cars, created]));
      }
      opBloc.add(FinishOperation(message: "Fahrzeug hinzugefügt"));
    } on CarsRepositoryException catch (e) {
      opBloc.add(FailOperation(message: e.message));
    } catch (_) {
      opBloc.add(
        FailOperation(message: "Fehler beim Anlegen eines Fahrzeugs"),
      );
    }
  }

  Future<void> _handleEdit(CarEdit event, Emitter<CarsState> emit) async {
    final current = state;
    opBloc.add(StartOperation());
    try {
      final updated = await repository.update(
        carId: event.carId,
        plate: event.plate,
        active: event.active,
      );
      _emitReplaced(current, updated, emit);
      opBloc.add(FinishOperation(message: "Fahrzeug aktualisiert"));
    } on CarsRepositoryException catch (e) {
      opBloc.add(FailOperation(message: e.message));
    } catch (_) {
      opBloc.add(
        FailOperation(message: "Fehler beim Aktualisieren des Fahrzeugs"),
      );
    }
  }

  Future<void> _handleDeactivate(
    CarDeactivate event,
    Emitter<CarsState> emit,
  ) async {
    final current = state;
    opBloc.add(StartOperation());
    try {
      await repository.update(carId: event.carId, active: false);
      if (current is CarsLoaded) {
        // Inaktive Fahrzeuge raus aus der UI-Liste — die Liste zeigt
        // nur aktive (Default).
        emit(
          current.copyWith(
            cars: current.cars
                .where((c) => c.id != event.carId)
                .toList(growable: false),
          ),
        );
      }
      opBloc.add(FinishOperation(message: "Fahrzeug deaktiviert"));
    } on CarsRepositoryException catch (e) {
      opBloc.add(FailOperation(message: e.message));
    } catch (_) {
      opBloc.add(
        FailOperation(message: "Fehler beim Deaktivieren des Fahrzeugs"),
      );
    }
  }

  void _emitReplaced(
    CarsState current,
    Car updated,
    Emitter<CarsState> emit,
  ) {
    if (current is! CarsLoaded) return;
    emit(
      current.copyWith(
        cars: current.cars
            .map((c) => c.id == updated.id ? updated : c)
            .toList(growable: false),
      ),
    );
  }
}
