import 'dart:async';

import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/ceiling_bloc/ceiling_sensor_event.dart';
import 'package:syncrow_app/features/devices/bloc/ceiling_bloc/ceiling_sensor_state.dart';
import 'package:syncrow_app/features/devices/model/ceiling_sensor_model.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/device_report_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';

class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
  final String deviceId;
  late DeviceModel deviceModel;
  late CeilingSensorModel deviceStatus;

  CeilingSensorBloc({required this.deviceId}) : super(InitialState()) {
    on<InitialEvent>(_fetchCeilingSensorStatus);
    on<ChangeValueEvent>(_changeValue);
    on<CeilingSensorUpdated>(_onCeilingSensorUpdated);
    on<ReportLogsInitial>(fetchLogsForLastMonth);
  }

  void _fetchCeilingSensorStatus(
      InitialEvent event, Emitter<CeilingSensorState> 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 = CeilingSensorModel.fromJson(statusModelList);
      emit(UpdateState(ceilingSensorModel: deviceStatus));
      _listenToChanges();
    } catch (e) {
      emit(FailedState(error: e.toString()));
      return;
    }
  }

  StreamSubscription<DatabaseEvent>? _streamSubscription;
  Timer? _timer;

  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 = CeilingSensorModel.fromJson(statusList);
        if (!isClosed) {
          add(CeilingSensorUpdated());
        }
      });
    } catch (_) {}
  }

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

  _onCeilingSensorUpdated(
      CeilingSensorUpdated event, Emitter<CeilingSensorState> emit) {
    emit(UpdateState(ceilingSensorModel: deviceStatus));
  }

  void _changeValue(
      ChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
    emit(LoadingNewSate(ceilingSensorModel: deviceStatus));
    try {
      final response = await DevicesAPI.controlDevice(
          DeviceControlModel(
              deviceId: deviceId, code: event.code, value: event.value),
          deviceId);
      if (response['success'] ?? false) {
        if (event.type == 'Sensitivity') {
          deviceStatus.sensitivity = event.value;
        } else if (event.type == 'Maximum Distance') {
          deviceStatus.movingMaxDis = event.value;
        } else if (event.type == 'Nobody Time') {
          deviceStatus.nobodyTime = event.value;
        } else if (event.type == 'Space Type') {
          deviceStatus.spaceType = SpaceTypes.values.firstWhere(
            (e) => e.name == event.value,
            orElse: () => SpaceTypes.none,
          );
        }
      } //scene
      emit(UpdateState(ceilingSensorModel: deviceStatus));
    } catch (_) {}
  }

  DeviceReport recordGroups =
      DeviceReport(startTime: '0', endTime: '0', data: []);

  Future<void> fetchLogsForLastMonth(
      ReportLogsInitial event, Emitter<CeilingSensorState> emit) async {
    DateTime now = DateTime.now();

    DateTime lastMonth = DateTime(now.year, now.month - 1, now.day);
    int startTime = lastMonth.millisecondsSinceEpoch;
    int endTime = now.millisecondsSinceEpoch;
    try {
      emit(LoadingInitialState());
      var response = await DevicesAPI.getReportLogs(
        startTime: startTime.toString(),
        endTime: endTime.toString(),
        deviceUuid: deviceId,
        code: 'presence_state',
      );
      recordGroups = response;
      // print('---${jsonEncode(recordGroups.data.first.)}');
      emit(FitchData());
    } on DioException catch (e) {
      final errorData = e.response!.data;
      String errorMessage = errorData['message'];
      emit(FailedState(error: errorMessage));
    }
  }
}
