import 'dart:async';

import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/wall_sensor_bloc/wall_sensor_state.dart';
import 'package:syncrow_app/features/devices/bloc/wall_sensor_bloc/wall_sensor_event.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/wall_sensor_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';

class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
  final String deviceId;
  late DeviceModel deviceModel;
  late WallSensorModel deviceStatus;

  WallSensorBloc({required this.deviceId}) : super(InitialState()) {
    on<InitialEvent>(_fetchCeilingSensorStatus);
    on<ChangeIndicatorEvent>(_changeIndicator);
    on<ChangeValueEvent>(_changeValue);
    on<WallSensorUpdatedEvent>(_wallSensorUpdated);
    on<GetDeviceReportsEvent>(_getDeviceReports);
  }

  void _fetchCeilingSensorStatus(
      InitialEvent event, Emitter<WallSensorState> emit) async {
    emit(LoadingInitialState());
    try {
      var response = await DevicesAPI.getDeviceStatus(deviceId);
      List<StatusModel> statusModelList = [];
      for (var status in response['status']) {
        statusModelList.add(StatusModel.fromJson(status));
      }
      deviceStatus = WallSensorModel.fromJson(statusModelList);
      emit(UpdateState(wallSensorModel: deviceStatus));
      _listenToChanges();
    } catch (e) {
      emit(FailedState(error: e.toString()));
      return;
    }
  }

  Timer? _timer;
  StreamSubscription<DatabaseEvent>? _streamSubscription;

  void _listenToChanges() {
    try {
      _streamSubscription?.cancel();
      DatabaseReference ref =
          FirebaseDatabase.instance.ref('device-status/$deviceId');
      Stream<DatabaseEvent> stream = ref.onValue;

      _streamSubscription = stream.listen((DatabaseEvent event) async {
        if (_timer != null) {
          await Future.delayed(const Duration(seconds: 2));
        }
        Map<dynamic, dynamic> usersMap =
            event.snapshot.value as Map<dynamic, dynamic>;
        List<StatusModel> statusList = [];
        usersMap['status'].forEach((element) {
          statusList
              .add(StatusModel(code: element['code'], value: element['value']));
        });
        deviceStatus = WallSensorModel.fromJson(statusList);
        if (!isClosed) {
          add(WallSensorUpdatedEvent());
        }
      });
    } catch (_) {}
  }

  @override
  Future<void> close() async {
    _streamSubscription?.cancel();
    _streamSubscription = null;
    return super.close();
  }

  _wallSensorUpdated(
      WallSensorUpdatedEvent event, Emitter<WallSensorState> emit) {
    emit(UpdateState(wallSensorModel: deviceStatus));
  }

  void _changeIndicator(
      ChangeIndicatorEvent event, Emitter<WallSensorState> emit) async {
    emit(LoadingNewSate(wallSensorModel: deviceStatus));
    try {
      final response = await DevicesAPI.controlDevice(
          DeviceControlModel(
              deviceId: deviceId, code: 'indicator', value: !event.value),
          deviceId);

      if (response['success'] ?? false) {
        deviceStatus.indicator = !event.value;
      }
    } catch (_) {}
    emit(UpdateState(wallSensorModel: deviceStatus));
  }

  void _changeValue(
      ChangeValueEvent event, Emitter<WallSensorState> emit) async {
    emit(LoadingNewSate(wallSensorModel: deviceStatus));
    try {
      final response = await DevicesAPI.controlDevice(
          DeviceControlModel(
              deviceId: deviceId, code: event.code, value: event.value),
          deviceId);

      if (response['success'] ?? false) {
        if (event.code == 'far_detection') {
          deviceStatus.farDetection = event.value;
        } else if (event.code == 'motionless_sensitivity') {
          deviceStatus.motionlessSensitivity = event.value;
        } else if (event.code == 'motion_sensitivity_value') {
          deviceStatus.motionSensitivity = event.value;
        }
      }
    } catch (_) {}
    emit(UpdateState(wallSensorModel: deviceStatus));
  }

  void _getDeviceReports(
      GetDeviceReportsEvent event, Emitter<WallSensorState> emit) async {
    emit(LoadingInitialState());

    try {
      await DevicesAPI.getDeviceReports(deviceId, event.code).then((value) {
        emit(DeviceReportsState(deviceReport: value, code: event.code));
      });
    } catch (e) {
      emit(FailedState(error: e.toString()));
      return;
    }
  }
}
