import 'dart:async';
import 'dart:developer';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/flush_sensor_bloc/flush_sensor_event.dart';
import 'package:syncrow_app/features/devices/bloc/flush_sensor_bloc/flush_sensor_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_info_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/flush_sensor_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';

class FlushSensorBloc extends Bloc<FlushSensorEvent, FlushSensorState> {
  final String deviceId;
  late DeviceModel deviceModel;
  late FlushSensorModel deviceStatus;

  FlushSensorBloc({required this.deviceId}) : super(FlushSensorInitialState()) {
    on<FlushSensorInitialEvent>(_fetchFlushSensorStatus);
    on<FlushSensorChangeIndicatorEvent>(_changeIndicator);
    on<FlushSensorChangeValueEvent>(_changeValue);
    on<FlushSensorUpdatedEvent>(_flushSensorUpdated);
    on<FlushSensorGetDeviceReportsEvent>(_getDeviceReports);
    on<FlushSensorInitialDeviseInfo>(fetchDeviceInfo);
  }

  void _fetchFlushSensorStatus(
      FlushSensorInitialEvent event, Emitter<FlushSensorState> emit) async {
    emit(FlushSensorLoadingInitialState());
    try {
      var response = await DevicesAPI.getDeviceStatus(deviceId);
      List<StatusModel> statusModelList = [];
      for (var status in response['status']) {
        statusModelList.add(StatusModel.fromJson(status));
      }
      deviceStatus = FlushSensorModel.fromJson(statusModelList);
      emit(FlushSensorUpdateState(flushSensorModel: deviceStatus));
      _listenToChanges();
    } catch (e) {
      emit(FlushSensorFailedState(error: e.toString()));
      return;
    }
  }

  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 {
        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 = FlushSensorModel.fromJson(statusList);
        if (!isClosed) {
          add(FlushSensorUpdatedEvent());
        }
      });
    } catch (_) {
      log(
        'Error listening to changes',
        name: 'FlushMountedPresenceSensorBloc._listenToChanges',
      );
    }
  }

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

  _flushSensorUpdated(
      FlushSensorUpdatedEvent event, Emitter<FlushSensorState> emit) {
    emit(FlushSensorUpdateState(flushSensorModel: deviceStatus));
  }

  void _changeIndicator(FlushSensorChangeIndicatorEvent event,
      Emitter<FlushSensorState> emit) async {
    emit(FlushSensorLoadingNewSate(flushSensorModel: deviceStatus));
    try {
      final response = await DevicesAPI.controlDevice(
          DeviceControlModel(
              deviceId: deviceId, code: 'indicator', value: !event.value),
          deviceId);
    } catch (e) {
      emit(FlushSensorFailedState(error: e.toString()));
      return;
    }
    emit(FlushSensorUpdateState(flushSensorModel: deviceStatus));
  }

  void _changeValue(
      FlushSensorChangeValueEvent event, Emitter<FlushSensorState> emit) async {
    emit(FlushSensorLoadingNewSate(flushSensorModel: deviceStatus));
    try {
      final response = await DevicesAPI.controlDevice(
          DeviceControlModel(
              deviceId: deviceId, code: event.code, value: event.value),
          deviceId);
    } catch (e) {
      emit(FlushSensorFailedState(error: e.toString()));
      return;
    }
    emit(FlushSensorUpdateState(flushSensorModel: deviceStatus));
  }

  void _getDeviceReports(FlushSensorGetDeviceReportsEvent event,
      Emitter<FlushSensorState> emit) async {
    emit(FlushSensorLoadingInitialState());
    try {
      await DevicesAPI.getReports(deviceId, event.code).then((value) {
        emit(FlushSensorDeviceReportsState(
            deviceReport: value, code: event.code));
      });
    } catch (e) {
      emit(FlushSensorFailedState(error: e.toString()));
      return;
    }
  }

  DeviceInfoModel deviceInfo = DeviceInfoModel(
    activeTime: 0,
    category: "",
    categoryName: "",
    createTime: 0,
    gatewayId: "",
    icon: "",
    ip: "",
    lat: "",
    localKey: "",
    lon: "",
    model: "",
    name: "",
    nodeId: "",
    online: false,
    ownerId: "",
    productName: "",
    sub: false,
    timeZone: "",
    updateTime: 0,
    uuid: "",
    productUuid: "",
    productType: "",
    permissionType: "",
    macAddress: "",
    subspace: Subspace(
      uuid: "",
      createdAt: "",
      updatedAt: "",
      subspaceName: "",
    ),
  );
  static String deviceName = '';

  void fetchDeviceInfo(FlushSensorInitialDeviseInfo event,
      Emitter<FlushSensorState> emit) async {
    try {
      emit(FlushSensorLoadingInitialState());
      var response = await DevicesAPI.getDeviceInfo(deviceId);
      deviceInfo = DeviceInfoModel.fromJson(response);
      deviceName = deviceInfo.name;
      emit(FlushSensorLoadingDeviceInfo(deviceInfo: deviceInfo));
    } catch (e) {
      emit(FlushSensorFailedState(error: e.toString()));
    }
  }
}
