import 'dart:async';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
import 'package:syncrow_app/features/devices/model/curtain_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/group_curtain_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';

class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
  double curtainWidth = 270;
  double curtainOpeningSpace = 195;
  double blindHeight = 310;
  double blindOpeningSpace = 245;
  double openPercentage = 0;
  bool isMoving = false;
  final String curtainId;

  CurtainBloc(
    this.curtainId,
  ) : super(CurtainInitial()) {
    on<InitCurtain>(_fetchStatus);
    on<OpenCurtain>(_onOpenCurtain);
    on<CloseCurtain>(_onCloseCurtain);
    on<PauseCurtain>(_onPauseCurtain);
    on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
    on<InitialWizardEvent>(_fetchWizardStatus);
    on<GroupAllOffEvent>(_groupAllOff);
    on<GroupAllOnEvent>(_groupAllOn);
    on<UpdateCurtainEvent>(_updateCurtain);
  }

  Future<void> _onOpenCurtain(
      OpenCurtain event, Emitter<CurtainState> emit) async {
    isMoving = true;
    while (openPercentage < 100.0) {
      if (state is CurtainsClosing) {
        _pauseCurtain(emit);
        break;
      }
      emit(CurtainsOpening(
        curtainWidth: curtainWidth,
        blindHeight: blindHeight,
        openPercentage: openPercentage,
      ));
      if (isMoving) {
        await Future.delayed(const Duration(milliseconds: 200), () async {
          openPercentage += 10.0;
          event.deviceType == DeviceType.Curtain
              ? curtainWidth -= curtainOpeningSpace / 10
              : blindHeight -= blindOpeningSpace / 10;
          if (openPercentage >= 100.0) {
            _pauseCurtain(emit);
          }
        });
        if (openPercentage >= 100.0) {
          await DevicesAPI.controlDevice(
            DeviceControlModel(
              deviceId: curtainId,
              code: 'control',
              value: 'close',
            ),
            curtainId,
          );
          await DevicesAPI.controlDevice(
            DeviceControlModel(
              deviceId: curtainId,
              code: 'percent_control',
              value: 100,
            ),
            curtainId,
          );
        }
      } else {
        _pauseCurtain(emit);
        break;
      }
    }
  }

  Future<void> _onCloseCurtain(
      CloseCurtain event, Emitter<CurtainState> emit) async {
    isMoving = true;
    while (openPercentage > 0.0) {
      if (state is CurtainsOpening) {
        _pauseCurtain(emit);
        break;
      }
      emit(CurtainsClosing(
        curtainWidth: curtainWidth,
        blindHeight: blindHeight,
        openPercentage: openPercentage,
      ));
      if (isMoving) {
        await Future.delayed(const Duration(milliseconds: 200), () async {
          openPercentage -= 10.0;
          event.deviceType == DeviceType.Curtain
              ? curtainWidth += curtainOpeningSpace / 10
              : blindHeight += blindOpeningSpace / 10;
          if (openPercentage <= 0.0) {
            _pauseCurtain(emit);
          }
        });
        if (openPercentage == 0.0) {
          await DevicesAPI.controlDevice(
            DeviceControlModel(
              deviceId: curtainId,
              code: 'percent_control',
              value: 0,
            ),
            curtainId,
          );
          await DevicesAPI.controlDevice(
            DeviceControlModel(
              deviceId: curtainId,
              code: 'control',
              value: 'open',
            ),
            curtainId,
          );
        }
      } else {
        _pauseCurtain(emit);
        break;
      }
    }
  }

  Future<void> _onPauseCurtain(
      PauseCurtain event, Emitter<CurtainState> emit) async {
    _pauseCurtain(emit);
    await DevicesAPI.controlDevice(
      DeviceControlModel(
        deviceId: curtainId,
        code: 'control',
        value: 'stop',
      ),
      curtainId,
    );
    await DevicesAPI.controlDevice(
      DeviceControlModel(
        deviceId: curtainId,
        code: 'percent_control',
        value: openPercentage.ceil(),
      ),
      curtainId,
    );
  }

  Future<void> _pauseCurtain(Emitter<CurtainState> emit) async {
    isMoving = false;
    emit(CurtainsPaused(
      curtainWidth: curtainWidth,
      blindHeight: blindHeight,
      openPercentage: openPercentage,
    ));
  }

  void _fetchStatus(InitCurtain event, Emitter<CurtainState> emit) async {
    try {
      emit(CurtainLoadingState());
      _listenToChanges(curtainId);

      var response = await DevicesAPI.getDeviceStatus(curtainId);

      List<StatusModel> statusModelList = [];
      for (var status in response['status']) {
        statusModelList.add(StatusModel.fromJson(status));
      }
      openPercentage = double.tryParse(statusModelList[1].value.toString())!;
      curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
      blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
      emit(CurtainsOpening(
        curtainWidth: curtainWidth,
        blindHeight: blindHeight,
        openPercentage: openPercentage,
      ));
    } catch (e) {
      emit(FailedState());
      return;
    }
  }

  StreamSubscription<DatabaseEvent>? _streamSubscription;

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

      _streamSubscription = stream.listen((DatabaseEvent event) {
        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']));
        });
        openPercentage = double.tryParse(statusList[1].value.toString())!;
        curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
        blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
        add(UpdateCurtainEvent());
      });
    } catch (_) {}
  }

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

  // _listenToChanges(curtainId) {
  //   try {
  //     print('curtainId=$curtainId');
  //     DatabaseReference ref =
  //         FirebaseDatabase.instance.ref('device-status/$curtainId');
  //     Stream<DatabaseEvent> stream = ref.onValue;

  //     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> statusModelList = [];
  //       for (var status in usersMap['status']) {
  //         statusModelList.add(StatusModel.fromJson(status));
  //         print('statusModelList==${statusModelList}');
  //       }

  //       openPercentage = double.tryParse(statusModelList[1].value.toString())!;
  //       curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
  //       blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
  //       add(UpdateCurtainEvent());
  //     });
  //   } catch (_) {}
  // }

  _updateCurtain(UpdateCurtainEvent event, Emitter<CurtainState> emit) {
    curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
    blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
    emit(CurtainsOpening(
      curtainWidth: curtainWidth,
      blindHeight: blindHeight,
      openPercentage: openPercentage,
    ));
  }

  List<GroupCurtainModel> groupList = [];
  bool allSwitchesOn = true;
  List<DeviceModel> devicesList = [];
  CurtainModel deviceStatus = CurtainModel(control: 'stop', percent: 0);
  void _fetchWizardStatus(
      InitialWizardEvent event, Emitter<CurtainState> emit) async {
    emit(LoadingInitialState());

    try {
      devicesList = [];
      groupList = [];
      allSwitchesOn = true;
      devicesList = await DevicesAPI.getDeviceByGroupName(
          HomeCubit.getInstance().selectedSpace?.id ?? '', 'CUR');

      for (int i = 0; i < devicesList.length; i++) {
        var response =
            await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
        List<StatusModel> statusModelList = [];
        for (var status in response['status']) {
          statusModelList.add(StatusModel.fromJson(status));
        }
        deviceStatus = CurtainModel.fromJson(statusModelList);
        groupList.add(GroupCurtainModel(
            deviceId: devicesList[i].uuid ?? '',
            deviceName: devicesList[i].name ?? '',
            firstSwitch: deviceStatus.control,
            percentControl: deviceStatus.percent));
      }

      if (groupList.isNotEmpty) {
        groupList.firstWhere((element) {
          if (element.percentControl > 1) {
            allSwitchesOn = true;
          }
          return true;
        });
      }
      emit(
          UpdateGroupState(curtainList: groupList, allSwitches: allSwitchesOn));
    } catch (e) {
      emit(FailedState());
      return;
    }
  }

  void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
      Emitter<CurtainState> emit) async {
    emit(LoadingNewSate(curtainModel: deviceStatus));
    try {
      bool allSwitchesValue = true;

      // Update the firstSwitch value in the groupList based on the deviceId
      groupList.forEach((element) {
        if (element.deviceId == event.deviceId) {
          element.percentControl =
              event.value; // Set the new value from the event
        }
        if (element.percentControl > 1) {
          allSwitchesValue = true; // Check if any switch is not 'open'
        }
      });

      final response = await DevicesAPI.deviceBatchController(
        code: 'percent_control',
        devicesUuid: [event.deviceId],
        value: event.value, // Use the value from the event
      );

      emit(UpdateGroupState(
          curtainList: groupList, allSwitches: allSwitchesValue));

      if (response['success']) {
        // Optionally add an initial event if needed.
      }
    } catch (_) {
      // Handle the error if needed.
    }
  }

  void _groupAllOn(GroupAllOnEvent event, Emitter<CurtainState> emit) async {
    emit(LoadingNewSate(curtainModel: deviceStatus));
    try {
      for (int i = 0; i < groupList.length; i++) {
        groupList[i].percentControl = 100;
      }

      emit(UpdateGroupState(curtainList: groupList, allSwitches: true));

      List<String> allDeviceIds =
          groupList.map((device) => device.deviceId).toList();

      final response2 = await DevicesAPI.deviceBatchController(
        code: 'percent_control',
        devicesUuid: allDeviceIds,
        value: 100,
      );

      if (response2['failedResults'].toString() != '[]') {
        await Future.delayed(const Duration(milliseconds: 500));
      }
    } catch (_) {
      emit(FailedState());
      await Future.delayed(const Duration(milliseconds: 500));
      // Optionally add an initial event if needed.
    }
  }

  void _groupAllOff(GroupAllOffEvent event, Emitter<CurtainState> emit) async {
    emit(LoadingNewSate(curtainModel: deviceStatus));
    try {
      for (int i = 0; i < groupList.length; i++) {
        groupList[i].percentControl = 0;
      }

      emit(UpdateGroupState(curtainList: groupList, allSwitches: false));

      List<String> allDeviceIds =
          groupList.map((device) => device.deviceId).toList();

      final response2 = await DevicesAPI.deviceBatchController(
        code: 'percent_control',
        devicesUuid: allDeviceIds,
        value: 0,
      );

      if (response2['failedResults'].toString() != '[]') {
        await Future.delayed(const Duration(milliseconds: 500));
      }
    } catch (_) {
      emit(FailedState());
      await Future.delayed(const Duration(milliseconds: 500));
    }
  }
}
