import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:syncrow_web/pages/analytics/services/realtime_device_service/realtime_device_service.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';

part 'realtime_device_changes_event.dart';
part 'realtime_device_changes_state.dart';

class RealtimeDeviceChangesBloc
    extends Bloc<RealtimeDeviceChangesEvent, RealtimeDeviceChangesState> {
  RealtimeDeviceChangesBloc(
    this._realtimeDeviceService,
  ) : super(const RealtimeDeviceChangesState()) {
    on<RealtimeDeviceChangesStarted>(_onRealtimeDeviceChangesStarted);
    on<RealtimeDeviceChangesClosed>(_onRealtimeDeviceChangesClosed);
    on<_RealtimeDeviceChangesUpdated>(_onRealtimeDeviceChangesUpdated);
  }

  final RealtimeDeviceService _realtimeDeviceService;
  StreamSubscription<List<Status>>? _subscription;

  Future<void> _onRealtimeDeviceChangesStarted(
    RealtimeDeviceChangesStarted event,
    Emitter<RealtimeDeviceChangesState> emit,
  ) async {
    await _subscription?.cancel();
    _subscription = _realtimeDeviceService.subscribe(event.deviceId).listen(
      (data) {
        add(_RealtimeDeviceChangesUpdated(data));
      },
      onError: (error) {
        emit(
          state.copyWith(
            status: RealtimeDeviceChangesStatus.failure,
            errorMessage: '$error',
          ),
        );
      },
    );
  }

  Future<void> _onRealtimeDeviceChangesClosed(
    RealtimeDeviceChangesClosed event,
    Emitter<RealtimeDeviceChangesState> emit,
  ) async {
    add(const _RealtimeDeviceChangesUpdated([]));
    await _subscription?.cancel();
    _subscription = null;
    emit(const RealtimeDeviceChangesState());
  }

  void _onRealtimeDeviceChangesUpdated(
    _RealtimeDeviceChangesUpdated event,
    Emitter<RealtimeDeviceChangesState> emit,
  ) {
    final currentState = state;
    final updatedList = [
      ...currentState.deviceStatusList.where(
        (device) => !event.deviceStatusList
            .any((newDevice) => newDevice.code == device.code),
      ),
      ...event.deviceStatusList,
    ];

    emit(
      state.copyWith(
        status: RealtimeDeviceChangesStatus.loaded,
        deviceStatusList: updatedList,
      ),
    );
  }

  @override
  Future<void> close() async {
    await _subscription?.cancel();
    return super.close();
  }
}
