  import 'dart:async';

  import 'package:bloc/bloc.dart';
  import 'package:equatable/equatable.dart';
  import 'package:firebase_database/firebase_database.dart';
  import 'package:flutter/foundation.dart';
  import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
  import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
  import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two_gang_glass_status_model.dart';
  import 'package:syncrow_web/services/batch_control_devices_service.dart';
  import 'package:syncrow_web/services/control_device_service.dart';
  import 'package:syncrow_web/services/devices_mang_api.dart';

  part 'two_gang_glass_switch_event.dart';
  part 'two_gang_glass_switch_state.dart';

  class TwoGangGlassSwitchBloc
      extends Bloc<TwoGangGlassSwitchEvent, TwoGangGlassSwitchState> {
    final String deviceId;
    final ControlDeviceService controlDeviceService;
    final BatchControlDevicesService batchControlDevicesService;

    late TwoGangGlassStatusModel deviceStatus;

    TwoGangGlassSwitchBloc({
      required this.deviceId,
      required this.controlDeviceService,
      required this.batchControlDevicesService,
    }) : super(TwoGangGlassSwitchInitial()) {
      on<TwoGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
      on<TwoGangGlassSwitchControl>(_onControl);
      on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
      on<TwoGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
      on<TwoGangGlassFactoryReset>(_onFactoryReset);
      on<StatusUpdated>(_onStatusUpdated);
    }

    Future<void> _onFetchDeviceStatus(
      TwoGangGlassSwitchFetchDeviceEvent event,
      Emitter<TwoGangGlassSwitchState> emit,
    ) async {
      emit(TwoGangGlassSwitchLoading());
      try {
        final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
        deviceStatus = TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
        _listenToChanges(event.deviceId);
        emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
      } catch (e) {
        emit(TwoGangGlassSwitchError(e.toString()));
      }
    }

    StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;

    void _listenToChanges(String deviceId) {
      try {
        final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
        _deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
          if (event.snapshot.value == null) return;

          final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;

          final statusList = <Status>[];

          usersMap['status'].forEach((element) {
            statusList.add(Status(code: element['code'], value: element['value']));
          });

          deviceStatus =
              TwoGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);

          add(StatusUpdated(deviceStatus));
        });
      } catch (_) {}
    }

    Future<void> _onControl(
      TwoGangGlassSwitchControl event,
      Emitter<TwoGangGlassSwitchState> emit,
    ) async {
      emit(TwoGangGlassSwitchLoading());
      _updateLocalValue(event.code, event.value);
      emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));

      try {
        await controlDeviceService.controlDevice(
          deviceUuid: event.deviceId,
          status: Status(code: event.code, value: event.value),
        );
      } catch (e) {
        _updateLocalValue(event.code, !event.value);
        emit(TwoGangGlassSwitchError(e.toString()));
      }
    }

    Future<void> _onBatchControl(
      TwoGangGlassSwitchBatchControl event,
      Emitter<TwoGangGlassSwitchState> emit,
    ) async {
      emit(TwoGangGlassSwitchLoading());
      _updateLocalValue(event.code, event.value);
      emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));

      try {
        await batchControlDevicesService.batchControlDevices(
          uuids: event.deviceIds,
          code: event.code,
          value: event.value,
        );
      } catch (e) {
        _updateLocalValue(event.code, !event.value);
        emit(TwoGangGlassSwitchError(e.toString()));
      }
    }

    Future<void> _onFetchBatchStatus(
      TwoGangGlassSwitchFetchBatchStatusEvent event,
      Emitter<TwoGangGlassSwitchState> emit,
    ) async {
      emit(TwoGangGlassSwitchLoading());
      try {
        final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
        deviceStatus = TwoGangGlassStatusModel.fromJson(
          event.deviceIds.first,
          status.status,
        );
        emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
      } catch (e) {
        emit(TwoGangGlassSwitchError(e.toString()));
      }
    }

    Future<void> _onFactoryReset(
      TwoGangGlassFactoryReset event,
      Emitter<TwoGangGlassSwitchState> emit,
    ) async {
      emit(TwoGangGlassSwitchLoading());
      try {
        final response = await DevicesManagementApi().factoryReset(
          event.factoryReset,
          event.deviceId,
        );
        if (!response) {
          emit(TwoGangGlassSwitchError('Failed to reset device'));
        } else {
          add(TwoGangGlassSwitchFetchDeviceEvent(event.deviceId));
        }
      } catch (e) {
        emit(TwoGangGlassSwitchError(e.toString()));
      }
    }

    void _onStatusUpdated(
      StatusUpdated event,
      Emitter<TwoGangGlassSwitchState> emit,
    ) {
      deviceStatus = event.deviceStatus;
      emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
    }

    void _updateLocalValue(String code, bool value) {
      switch (code) {
        case 'switch_1':
          deviceStatus = deviceStatus.copyWith(switch1: value);
          break;
        case 'switch_2':
          deviceStatus = deviceStatus.copyWith(switch2: value);
          break;
      }
    }

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