import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
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/app_layout/model/community_model.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_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/device_report_model.dart';
import 'package:syncrow_app/features/devices/model/question_model.dart';
import 'package:syncrow_app/features/devices/model/sos_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/navigation/routing_constants.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 SosBloc extends Bloc<SosEvent, SosState> {
  final String sosId;
  SosBloc({
    required this.sosId,
  }) : super(const SosState()) {
    on<SosInitial>(_fetchStatus);
    on<ReportLogsInitial>(fetchLogsForLastMonth);
    on<ToggleEnableAlarmEvent>(_toggleLowBattery);
    on<ToggleClosingReminderEvent>(_toggleClosingReminder);
    on<ChangeNameEvent>(_changeName);
    on<SearchFaqEvent>(_onSearchFaq);
    on<SosInitialQuestion>(_onSosInitial);
    on<FetchRoomsEvent>(_fetchRoomsAndDevices);
    on<SelectOptionEvent>(_onOptionSelected);
    on<SaveSelectionEvent>(_onSaveSelection);
    on<AssignRoomEvent>(_assignDevice);
    on<SosInitialDeviseInfo>(fetchDeviceInfo);
    on<SaveNameEvent>(saveName);
    on<ToggleUpdateEvent>(_toggleUpdate);
    on<ToggleHelpfulEvent>(_toggleHelpful);
  }

  final TextEditingController nameController =
      TextEditingController(text: deviceName);
  bool isSaving = false;
  bool editName = false;
  final FocusNode focusNode = FocusNode();
  bool enableAlarm = false;
  bool closingReminder = false;
  SosModel deviceStatus =
      SosModel(sosContactState: 'sos', batteryPercentage: 0);

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

  void _toggleLowBattery(
      ToggleEnableAlarmEvent event, Emitter<SosState> emit) async {
    emit(LoadingNewSate(sosSensor: deviceStatus));
    try {
      enableAlarm = event.isLowBatteryEnabled;
      emit(UpdateState(sensor: deviceStatus));
      await DevicesAPI.controlDevice(
        DeviceControlModel(
          deviceId: sosId,
          code: 'low_battery',
          value: enableAlarm,
        ),
        sosId,
      );
    } catch (e) {
      emit(SosFailedState(errorMessage: e.toString()));
    }
  }

  void _toggleClosingReminder(
      ToggleClosingReminderEvent event, Emitter<SosState> emit) async {
    emit(LoadingNewSate(sosSensor: deviceStatus));
    try {
      closingReminder = event.isClosingReminderEnabled;
      emit(UpdateState(sensor: deviceStatus));
    } catch (e) {
      emit(SosFailedState(errorMessage: e.toString()));
    }
  }

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

  Future<void> fetchLogsForLastMonth(
      ReportLogsInitial event, Emitter<SosState> 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(SosLoadingState());
      var response = await DevicesAPI.getReportLogs(
        startTime: startTime.toString(),
        endTime: endTime.toString(),
        deviceUuid: sosId,
        code: 'sos',
      );
      recordGroups = response;
      emit(UpdateState(sensor: deviceStatus));
    } on DioException catch (e) {
      final errorData = e.response!.data;
      String errorMessage = errorData['message'];
      emit(SosFailedState(errorMessage: e.toString()));
    }
  }

//========================= Device Info & Status =============================

  static String deviceName = '';

  fetchDeviceInfo(SosInitialDeviseInfo event, Emitter<SosState> emit) async {
    try {
      emit(SosLoadingState());
      var response = await DevicesAPI.getDeviceInfo(sosId);
      deviceInfo = DeviceInfoModel.fromJson(response);
      deviceName = deviceInfo.name;
      emit(LoadingSosDeviceInfo(deviceInfo: deviceInfo));
    } catch (e) {
      emit(SosFailedState(errorMessage: e.toString()));
    }
  }

  void _fetchStatus(SosInitial event, Emitter<SosState> emit) async {
    emit(SosLoadingState());
    try {
      var response = await DevicesAPI.getDeviceStatus(sosId);
      List<StatusModel> statusModelList = [];
      for (var status in response['status']) {
        statusModelList.add(StatusModel.fromJson(status));
      }
      deviceStatus = SosModel.fromJson(
        statusModelList,
      );
      emit(UpdateState(sensor: deviceStatus));
      Future.delayed(const Duration(milliseconds: 500));
      // _listenToChanges();
    } catch (e) {
      emit(SosFailedState(errorMessage: e.toString()));
      return;
    }
  }

//========================= assign & unassign  devise to room =============================
  List<DeviceModel> allDevices = [];
  List<SubSpaceModel> roomsList = [];
  void _fetchRoomsAndDevices(
      FetchRoomsEvent event, Emitter<SosState> emit) async {
    try {
      emit(SosLoadingState());
      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 SosFailedState(errorMessage: 'Something went wrong'));
      return;
    }
  }

  String roomId = '';
  SpaceModel unit =
      SpaceModel(id: '', name: '', community: Community(uuid: '', name: ''));

  String _selectedOption = '';
  bool _hasSelectionChanged = false;

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

  void _onSaveSelection(SaveSelectionEvent event, Emitter<SosState> emit) {
    if (_hasSelectionChanged) {
      _hasSelectionChanged = false;
      add(AssignRoomEvent(roomId: roomId, unit: unit, context: event.context));
      emit(SaveSelectionSuccessState());
      var cubit = HomeCubit.getInstance();
      cubit.updatePageIndex(1);
      Navigator.pushReplacementNamed(event.context, Routes.homeRoute);
    }
  }

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

      await HomeManagementAPI.assignDeviceToRoom(
          event.unit.community.uuid,
          event.unit.id,
          event.roomId,
          sosId,
          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 SosFailedState(errorMessage: 'Something went wrong'));
      return;
    }
  }

  void _unassignDevice(UnassignRoomEvent event, Emitter<SosState> emit) async {
    try {
      Map<String, bool> roomDevicesId = {};
      Project? project = HomeCubit.getInstance().project;

      emit(SosLoadingState());
      await HomeManagementAPI.unAssignDeviceToRoom(
          event.unit.community.uuid, event.unit.id, event.roomId, sosId, 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!);
      });

      devicesList.forEach((e) {
        if (allDevicesIds.contains(e.uuid!)) {
          roomDevicesId[e.uuid!] = true;
        } else {
          roomDevicesId[e.uuid!] = false;
        }
      });
    } catch (e) {
      emit(const SosFailedState(errorMessage: 'Something went wrong'));
      return;
    }
  }

  Map<String, List<DeviceModel>> devicesByRoom = {};

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

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

  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;
  }

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

//============================== update setting ===============================
  bool enableUpdate = false;

  void _toggleUpdate(ToggleUpdateEvent event, Emitter<SosState> emit) async {
    try {
      emit(SosLoadingState());
      enableUpdate = event.isUpdateEnabled!;
      emit(SaveState());
    } catch (e) {
      emit(SosFailedState(errorMessage: e.toString()));
    }
  }

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

  final List<QuestionModel> faqQuestions = [
    QuestionModel(
      id: 1,
      question: 'How does an SOS emergency button work?',
      answer:
          'The SOS emergency button sends an alert to your contacts when pressed.',
    ),
    QuestionModel(
      id: 2,
      question: 'How long will an SOS alarm persist?',
      answer:
          'The SOS alarm will persist until it is manually turned off or after a set time.',
    ),
    QuestionModel(
      id: 3,
      question: 'What should I do if the SOS button is unresponsive?',
      answer: 'Try restarting the device. If it persists, contact support.',
    ),
    QuestionModel(
      id: 4,
      question: 'Can I use the SOS feature without a network connection?',
      answer:
          'No, a network connection is required to send the alert to your contacts.',
    ),
    QuestionModel(
      id: 5,
      question: 'How often should I check the SOS battery?',
      answer:
          'Check the SOS battery at least once a month to ensure it is operational.',
    ),
  ];

  Future<void> _onSosInitial(
      SosInitialQuestion event, Emitter<SosState> emit) async {
    emit(SosLoadingState());
    emit(FaqLoadedState(filteredFaqQuestions: faqQuestions));
  }

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

  bool isHelpful = false;
  void _toggleHelpful(ToggleHelpfulEvent event, Emitter<SosState> emit) async {
    try {
      emit(SosLoadingState());
      isHelpful = event.isHelpful!;
      emit(SaveState());
    } catch (e) {
      emit(SosFailedState(errorMessage: e.toString()));
    }
  }

//===================== delete Device ===================================

  deleteDevice(DeleteDeviceEvent event, Emitter<SosState> emit) async {
    try {
      emit(SosLoadingState());
      var response = await DevicesAPI.resetDevise(devicesUuid: sosId);
      add(SosInitialDeviseInfo());
      add(const SosInitial());
      CustomSnackBar.displaySnackBar('Reset Successfully');
    } catch (e) {
      emit(SosFailedState(errorMessage: e.toString()));
    }
  }


  //real-time db
  // StreamSubscription<DatabaseEvent>? _streamSubscription;
  // Timer? _timer;

  // void _listenToChanges() {
  //   try {
  //     _streamSubscription?.cancel();
  //     DatabaseReference ref =
  //         FirebaseDatabase.instance.ref('device-status/$sosId');
  //     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 = SosModel.fromJson(statusList);
  //     });
  //   } catch (_) {}
  // }

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