import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/devices/bloc/device_settings_bloc/device_scene_event.dart';
import 'package:syncrow_app/features/devices/bloc/device_settings_bloc/device_scene_state.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/four_scene_model.dart';
import 'package:syncrow_app/features/devices/model/four_scene_switch_model.dart';
import 'package:syncrow_app/features/devices/model/question_model.dart';
import 'package:syncrow_app/features/devices/model/group_devices_model.dart';
import 'package:syncrow_app/features/devices/model/device_info_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/home_management_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';

class DeviceSettingBloc extends Bloc<DeviceSettingEvent, DeviceSettingState> {
  final String deviceId;
  DeviceSettingBloc({
    required this.deviceId,
  }) : super(const DeviceSettingState()) {
    on<DeviceSettingInitial>(_fetchDeviceStatus);
    on<DeviceSettingInitialInfo>(fetchDeviceInfo);
    on<SaveNameEvent>(saveName);
    on<ToggleNotificationEvent>(_toggleNotification);
    on<ChangeNameEvent>(_changeName);
    on<SearchFaqEvent>(_onSearchFaq);
    on<FetchRoomsEvent>(_fetchRoomsAndDevices);
    on<LoadSettings>(_onLoadSettings);
    on<SearchSettingsEvent>(searchSetting);
    on<AssignRoomEvent>(_assignDevice);
    on<AddDeviceToGroup>(_addDeviceToGroup);
    on<RemoveDeviceFromGroup>(_removeDeviceFromGroup);
    on<DeviceSettingInitialQuestion>(_onDeviceSettingInitial);
    on<FetchDeviceSetting>(_fetchDeviceSetting);
    on<GetSettingBySwitchName>(getSettingByName);
    on<SelectSettingEvent>(_selectSetting);
    on<DeleteDeviceEvent>(deleteDevice);
    on<ToggleEnableAlarmEvent>(_toggleLowBattery);
    on<ToggleUpdateEvent>(_toggleUpdate);
    on<ToggleHelpfulEvent>(_toggleHelpful);
    on<SelectOptionEvent>(_onOptionSelected);
  }

  final TextEditingController nameController =
      TextEditingController(text: deviceName);
  bool isSaving = false;
  bool editName = false;
  final FocusNode focusNode = FocusNode();
  bool closingReminder = false;
  bool waterAlarm = false;
  static String deviceName = '';
  static String selectedRoomId = '';
  bool selecedSetting = false;
  bool enableAlarm = false;
  List<FourSceneSwitchModel> fourSetting = [];

  String _selectedOption = '';
  bool _hasSelectionChanged = false;

  FourSceneModelState deviceStatus = FourSceneModelState(
      scene_1: '',
      scene_2: '',
      scene_3: '',
      scene_4: '',
      scene_id_group_id: '',
      switch_backlight: false);

  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: "",
    ),
  );

//============================ get Setting and assign scene =======================
  String selectedFormApiSettingId = '';
  String selectedSettingId = '';

  _selectSetting(SelectSettingEvent event, Emitter<DeviceSettingState> emit) {
    emit(DeviceSettingLoadingState());
    selectedSettingId = event.selectedSettingId;
    emit(SettingSelectionUpdatedState(selectedSettingId: selectedSettingId));
  }

  void getSettingByName(
      GetSettingBySwitchName event, Emitter<DeviceSettingState> emit) async {
    // emit(DeviceSettingLoadingState());
    try {
      final response = await DevicesAPI.getSceneBySwitchName(
          deviceId: deviceId, switchName: event.switchName);
      selectedFormApiSettingId = response['scene']['uuid'];
      emit(UpdateState(device: deviceStatus));
    } catch (e) {
      emit(DeviceSettingFailedState(errorMessage: e.toString()));
    }
  }

  void _fetchDeviceSetting(
      FetchDeviceSetting event, Emitter<DeviceSettingState> emit) async {
    emit(DeviceSettingLoadingState());
    try {
      var response = await DevicesAPI.getDeviceStatus(deviceId);
      List<StatusModel> statusModelList = [];
      for (var status in response['status']) {
        statusModelList.add(StatusModel.fromJson(status));
      }
      deviceStatus = FourSceneModelState.fromJson(
        statusModelList,
      );
      emit(UpdateState(device: deviceStatus));
      Future.delayed(const Duration(milliseconds: 500));
    } catch (e) {
      emit(DeviceSettingFailedState(errorMessage: e.toString()));
      return;
    }
  }

//=====================  fetch Device Status and info =======================

  void _toggleLowBattery(
      ToggleEnableAlarmEvent event, Emitter<DeviceSettingState> emit) async {
    emit(LoadingNewSate(device: deviceStatus));
    try {
      enableAlarm = event.isLowBatteryEnabled;
      emit(UpdateState(device: deviceStatus));
    } catch (e) {
      emit(DeviceSettingFailedState(errorMessage: e.toString()));
    }
  }

  void _fetchDeviceStatus(
      DeviceSettingInitial event, Emitter<DeviceSettingState> emit) async {
    emit(DeviceSettingLoadingState());
    try {
      var response = await DevicesAPI.getDeviceStatus(deviceId);
      List<StatusModel> statusModelList = [];
      for (var status in response['status']) {
        statusModelList.add(StatusModel.fromJson(status));
      }
      deviceStatus = FourSceneModelState.fromJson(
        statusModelList,
      );
      emit(SuccessState());
      //  add(const DeviceSettingSwitchInitial());
    } catch (e) {
      emit(DeviceSettingFailedState(errorMessage: e.toString()));
      return;
    }
  }

  Future fetchDeviceInfo(
      DeviceSettingInitialInfo event, Emitter<DeviceSettingState> emit) async {
    try {
      emit(DeviceSettingLoadingState());
      var response = await DevicesAPI.getDeviceInfo(deviceId);
      deviceInfo = DeviceInfoModel.fromJson(response);
      deviceName = deviceInfo.name;
      emit(LoadingDeviceInfo(deviceInfo: deviceInfo));
    } catch (e) {
      emit(DeviceSettingFailedState(errorMessage: e.toString()));
    }
  }

  void _onSearchFaq(SearchFaqEvent event, Emitter<DeviceSettingState> emit) {
    emit(DeviceSettingLoadingState());
    List<QuestionModel> _faqQuestions = faqQuestions.where((question) {
      return question.question
          .toLowerCase()
          .contains(event.query.toLowerCase());
    }).toList();
    emit(FaqSearchState(filteredFaqQuestions: _faqQuestions));
  }

//============================ assign Device  ==================================
//////////////////////////////////////////////////////////////////////////////

  void _toggleNotification(
      ToggleNotificationEvent event, Emitter<DeviceSettingState> emit) async {
    emit(LoadingNewSate(device: deviceStatus));
    try {
      enableAlarm = event.isClosingEnabled;
      emit(UpdateState(device: deviceStatus));
    } catch (e) {
      emit(DeviceSettingFailedState(errorMessage: e.toString()));
    }
  }

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

  //========================= Question and faq ================================

  final List<QuestionModel> faqQuestions = [
    QuestionModel(
      id: 1,
      question:
          'How does an 4 Setting Switch work? How long will an 4 Setting Switch persist?',
      answer:
          'Yes. In scenes with high detection requirements, we recommend that you choose phone or message notification in Automation.',
    ),
    QuestionModel(
      id: 2,
      question: 'Does the 4 Setting Switch support sending notifications?',
      answer:
          'The SOS alarm will persist until it is manually turned off or after a set time.',
    ),
    QuestionModel(
      id: 3,
      question:
          'Why does the data statistics in the device panel not show the correct data?',
      answer: 'Try restarting the device. If it persists, contact support.',
    ),
    QuestionModel(
      id: 4,
      question:
          'How long will the App show offline after a device (low-power devices and normal devices) is powered...',
      answer:
          'No, a network connection is required to send the alert to your contacts.',
    ),
  ];

  bool? isHelpful;

  void _toggleHelpful(
      ToggleHelpfulEvent event, Emitter<DeviceSettingState> emit) async {
    try {
      emit(DeviceSettingLoadingState());
      isHelpful = event.isHelpful!;
      emit(SaveState());
    } catch (e) {
      emit(
          const DeviceSettingFailedState(errorMessage: 'Something went wrong'));
    }
  }

  Future<void> _onDeviceSettingInitial(DeviceSettingInitialQuestion event,
      Emitter<DeviceSettingState> emit) async {
    emit(DeviceSettingLoadingState());
    emit(FaqLoadedState(filteredFaqQuestions: faqQuestions));
  }

  List<DeviceModel> allDevices = [];
  List<SubSpaceModel> roomsList = [];
  bool switchStatus = true;

  Future<void> _onLoadSettings(
      LoadSettings event, Emitter<DeviceSettingState> emit) async {
    emit(DeviceSettingLoadingState());
    try {
      if (event.unitId.isNotEmpty) {
        // allSettings = await DevicesAPI.getDveByUnitId(
        //     event.unitId, event.unit.community.uuid,
        //     showInDevice: event.showInDevice);

        filteredSettings = allSettings;
        emit(SettingLoaded(allSettings));
      } else {
        emit(const DeviceSettingFailedState(errorMessage: 'Unit ID is empty'));
      }
    } catch (e) {
      emit(
          const DeviceSettingFailedState(errorMessage: 'Something went wrong'));
    }
  }

  List<ScenesModel> allSettings = [];
  List<ScenesModel> filteredSettings = [];

  void searchSetting(
      SearchSettingsEvent event, Emitter<DeviceSettingState> emit) {
    emit(DeviceSettingLoadingState());
    filteredSettings = event.query.isEmpty
        ? allSettings
        : allSettings.where((scene) {
            final sceneName = scene.name?.toLowerCase() ?? '';
            return sceneName.contains(event.query.toLowerCase());
          }).toList();
    emit(SearchResultsState());
  }

  List<GroupDevicesModel> groupDevices = [
    GroupDevicesModel(
        dec: 'Syncroom', icon: Assets.minusIcon, name: '6 Setting Switch')
  ];

  List<GroupDevicesModel> devices = [
    GroupDevicesModel(
        dec: 'Syncroom', icon: Assets.addDevicesIcon, name: '6 Setting Switch')
  ];

  // Handler for AddDeviceToGroup
  void _addDeviceToGroup(
      AddDeviceToGroup event, Emitter<DeviceSettingState> emit) {
    devices.remove(event.device);
    groupDevices.add(event.device);
    for (var device in groupDevices) {
      device.icon = event.icon;
    }
    emit(UpdateStateList(groupDevices: groupDevices, devices: devices));
  }

  // Handler for RemoveDeviceFromGroup
  void _removeDeviceFromGroup(
      RemoveDeviceFromGroup event, Emitter<DeviceSettingState> emit) {
    groupDevices.remove(event.device);
    devices.add(event.device);
    for (var device in groupDevices) {
      device.icon = event.icon;
    }
    emit(UpdateStateList(groupDevices: groupDevices, devices: devices));
  }

  //=========================== assign device to room ==========================

  void _assignDevice(
      AssignRoomEvent event, Emitter<DeviceSettingState> emit) async {
    try {
      emit(DeviceSettingLoadingState());
      Project? project = HomeCubit.getInstance().project;

      if (_hasSelectionChanged) {
        await HomeManagementAPI.assignDeviceToRoom(
            event.unit.community.uuid,
            event.unit.id,
            event.roomId,
            deviceId,
            project?.uuid ?? TempConst.projectIdDev);
        final devicesList = await DevicesAPI.getDevicesByRoomId(
            communityUuid: event.unit.community.uuid,
            spaceUuid: event.unit.id,
            roomId: event.roomId,
            projectId: project?.uuid ?? TempConst.projectIdDev);
        List<String> allDevicesIds = [];
        allDevices.forEach((element) {
          allDevicesIds.add(element.uuid!);
        });
        await HomeCubit.getInstance().fetchUnitsByUserId();
        CustomSnackBar.displaySnackBar('Save Successfully');
        emit(SaveSelectionSuccessState());
      }
    } catch (e) {
      emit(
          const DeviceSettingFailedState(errorMessage: 'Something went wrong'));
      return;
    }
  }

  void _fetchRoomsAndDevices(
      FetchRoomsEvent event, Emitter<DeviceSettingState> emit) async {
    try {
      emit(DeviceSettingLoadingState());
      Project? project = HomeCubit.getInstance().project;

      roomsList = await SpacesAPI.getSubSpaceBySpaceId(
          event.unit.community.uuid,
          event.unit.id,
          project?.uuid ?? TempConst.projectIdDev);
      emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
    } catch (e) {
      emit(
          const DeviceSettingFailedState(errorMessage: 'Something went wrong'));
      return;
    }
  }

//============================ setting name ==================================
//////////////////////////////////////////////////////////////////////////////

  void _changeName(ChangeNameEvent event, Emitter<DeviceSettingState> emit) {
    emit(DeviceSettingLoadingState());
    editName = event.value!;
    if (editName) {
      Future.delayed(const Duration(milliseconds: 500), () {
        focusNode.requestFocus();
      });
    } else {
      focusNode.unfocus();
    }
    emit(NameEditingState(editName: editName));
  }

  bool _validateInputs() {
    final nameError = fullNameValidator(nameController.text);
    if (nameError != null) {
      CustomSnackBar.displaySnackBar(nameError);
      return true;
    }
    return false;
  }

  String? fullNameValidator(String? value) {
    if (value == null) return 'name is required';
    final withoutExtraSpaces = value.replaceAll(RegExp(r"\s+"), ' ').trim();
    if (withoutExtraSpaces.length < 2 || withoutExtraSpaces.length > 30) {
      return 'name must be between 2 and 30 characters long';
    }
    if (RegExp(r"/[^ a-zA-Z0-9-\']/").hasMatch(withoutExtraSpaces)) {
      return 'Only alphanumeric characters, space, dash and single quote are allowed';
    }
    return null;
  }

  Future<void> saveName(
      SaveNameEvent event, Emitter<DeviceSettingState> emit) async {
    if (_validateInputs()) return;
    try {
      add(const ChangeNameEvent(value: false));
      isSaving = true;
      emit(DeviceSettingLoadingState());
      var response = await DevicesAPI.putDeviceName(
          deviceId: deviceId, deviceName: nameController.text);
      add(const DeviceSettingInitialInfo());
      await HomeCubit.getInstance().fetchUnitsByUserId();
      CustomSnackBar.displaySnackBar('Save Successfully');
      emit(SaveState());
    } catch (e) {
      emit(DeviceSettingFailedState(errorMessage: e.toString()));
    } finally {
      isSaving = false;
    }
  }

//====================== update device ==============================

  bool enableUpdate = false;

  void _toggleUpdate(
      ToggleUpdateEvent event, Emitter<DeviceSettingState> emit) async {
    try {
      emit(DeviceSettingLoadingState());
      enableUpdate = event.isUpdateEnabled!;
      emit(SaveState());
    } catch (e) {
      emit(
          const DeviceSettingFailedState(errorMessage: 'Something went wrong'));
    }
  }

  deleteDevice(
      DeleteDeviceEvent event, Emitter<DeviceSettingState> emit) async {
    try {
      emit(DeviceSettingLoadingState());
      var response = await DevicesAPI.resetDevise(devicesUuid: deviceId);
      CustomSnackBar.displaySnackBar('Reset Successfully');
      emit(UpdateState(device: deviceStatus));
    } catch (e) {
      emit(DeviceSettingFailedState(errorMessage: e.toString()));
      return;
    }
  }

  void _onOptionSelected(
      SelectOptionEvent event, Emitter<DeviceSettingState> emit) {
    emit(DeviceSettingLoadingState());
    _selectedOption = event.selectedOption;
    _hasSelectionChanged = true;
    emit(OptionSelectedState(
        selectedOption: _selectedOption,
        hasSelectionChanged: _hasSelectionChanged));
  }
}
