import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:mc_common_app/classes/consts.dart';
import 'package:mc_common_app/config/routes.dart';
import 'package:mc_common_app/extensions/int_extensions.dart';
import 'package:mc_common_app/extensions/string_extensions.dart';
import 'package:mc_common_app/generated/locale_keys.g.dart';
import 'package:mc_common_app/main.dart';
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
import 'package:mc_common_app/models/appointments_models/appointment_slots.dart';
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
import 'package:mc_common_app/models/general_models/enums_model.dart';
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
import 'package:mc_common_app/models/general_models/m_response.dart';
import 'package:mc_common_app/models/general_models/widgets_models.dart';
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/categroy.dart';
import 'package:mc_common_app/models/provider_branches_models/profile/services.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_model.dart';
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
import 'package:mc_common_app/models/services_models/item_model.dart';
import 'package:mc_common_app/models/services_models/service_model.dart';
import 'package:mc_common_app/repositories/appointment_repo.dart';
import 'package:mc_common_app/repositories/branch_repo.dart';
import 'package:mc_common_app/repositories/common_repo.dart';
import 'package:mc_common_app/services/common_services.dart';
import 'package:mc_common_app/theme/colors.dart';
import 'package:mc_common_app/utils/enums.dart';
import 'package:mc_common_app/utils/navigator.dart';
import 'package:mc_common_app/utils/utils.dart';
import 'package:mc_common_app/view_models/base_view_model.dart';
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
import 'package:mc_common_app/view_models/payment_view_model.dart';
import 'package:mc_common_app/views/appointments/book_appointment_schedules_view.dart';
import 'package:mc_common_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart';
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';

class AppointmentsVM extends BaseVM {
  final CommonRepo commonRepo;
  final CommonAppServices commonServices;
  final BranchRepo branchRepo;
  final AppointmentRepo appointmentRepo;

  AppointmentsVM({required this.commonServices, required this.appointmentRepo, required this.commonRepo, required this.branchRepo});

  bool isUpcommingEnabled = true;
  bool isFetchingLists = false;
  int selectedBranch = 0;
  int selectedAppointmentIndex = 0;
  int selectedAppointmentSubIndex = 0;
  int selectedAppointmentId = 0;

  List<AppointmentListModel> myAppointments = [];
  List<AppointmentListModel> myUpComingAppointments = [];
  List<AppointmentListModel> myFilteredAppointments = [];
  List<FilterListModel> appointmentsFilterOptions = [];
  List<CustomerData> customersAppointments = [];
  List<AppointmentListModel> myFilteredAppointments2 = [];

  // List<ScheduleData> availableSchedules = [];

  bool isFetchingServices = false;

  List<DropValue> branchCategories = [];

  bool isHomeTapped = false;
  bool isShowEmptyMessage = false;

  List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleList = [];

  bool ifItemAlreadySelected(int id) {
    int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id);
    if (indexFound != -1) {
      return true;
    }
    return false;
  }

  List<ItemData> allSelectedItemsInAppointments = [];

  // setupProviderAppointmentFilter() {
  //   appointmentsFilterOptions.clear();
  //   appointmentsFilterOptions.add(FilterListModel(id: 0, title: "All Appointments", isSelected: true));
  //   appointmentsFilterOptions.add(FilterListModel(id: 2, title: "Confirmed", isSelected: false));
  //   appointmentsFilterOptions.add(FilterListModel(id: 3, title: "Arrived", isSelected: false));
  //   appointmentsFilterOptions.add(FilterListModel(id: 7, title: "Work In Progress", isSelected: false));
  //   appointmentsFilterOptions.add(FilterListModel(id: 8, title: "Completed", isSelected: false));
  //   appointmentsFilterOptions.add(FilterListModel(id: 4, title: "Canceled", isSelected: false));
  // }

  Future<void> onItemsSelectedInService() async {
    if (currentServiceSelection != null) {
      int index = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!);

      if (index == -1) {
        double totalPrice = 0.0;
        for (var element in currentServiceSelection!.serviceItems!) {
          totalPrice = totalPrice + double.parse(element.price ?? "0.0");
        }
        currentServiceSelection!.currentTotalServicePrice = totalPrice;
        servicesInCurrentAppointment.insert(0, currentServiceSelection!);
      }

      resetCategorySelectionBottomSheet();
      notifyListeners();
    }
  }

  Future<void> onPayNowPressedForAppointment({required BuildContext context, required int appointmentID}) async {
    context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: [appointmentID]);
    navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.partialAppointment);
  }

  Future<void> onBookAppointmentPressed(BuildContext context) async {
    Utils.showLoading(context);
    bool isSuccess = false;
    List<int> appointmentIdsList = [];
    try {
      GenericRespModel genericRespModel = await appointmentRepo.createServiceAppointment(
        schedules: serviceAppointmentScheduleList,
        serviceProviderID: selectedBranchModel!.serviceProviderId ?? 0,
      );

      if (genericRespModel.data.isEmpty) {
        Utils.hideLoading(context);
        Utils.showToast("${genericRespModel.message.toString()}");
        return;
      }

      if (genericRespModel.data != null && genericRespModel.data.isNotEmpty) {
        genericRespModel.data.forEach((element) {
          if (element['appointmentID'] != 0) {
            appointmentIdsList.add(element['appointmentID']);
            isSuccess = true;
          } else {
            isSuccess = false;
            Utils.showToast(element['message']);

            return;
          }
        });
      }

      context.read<DashboardVmCustomer>().onNavbarTapped(1);
      applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.booked);
      Utils.hideLoading(context);
      resetAfterBookingAppointment();
      if (isSuccess) {
        if (amountToPayForAppointment > 0) {
          context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: appointmentIdsList);
          navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
        } else {
          Utils.showToast(LocaleKeys.appointmentBookedSuccessfully.tr());
          getMyAppointments();
          navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
        }
      }
    } catch (e) {
      Utils.showToast("${e.toString()}");
    }
  }

  Future<void> onConfirmAppointmentPressed({required BuildContext context, required appointmentId}) async {
    context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: [appointmentId]);
    navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
  }

  Future<void> onCancelAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
    Utils.showLoading(context);
    try {
      GenericRespModel genericRespModel = await appointmentRepo.cancelOrRescheduleServiceAppointment(
        serviceAppointmentID: appointmentListModel.id ?? 0,
        serviceSlotID: appointmentListModel.serviceSlotID ?? 0,
        appointmentScheduleAction: 2, // 1 for Reschedule and 2 for Cancel
      );

      if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
        Utils.hideLoading(context);
        Utils.showToast("${genericRespModel.message.toString()}");
        return;
      }
      if (genericRespModel.messageStatus == 1) {
        context.read<DashboardVmCustomer>().onNavbarTapped(1);
        applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
        Utils.showToast("${genericRespModel.message.toString()}");
        await getMyAppointments();
        Utils.hideLoading(context);
        getMyAppointments();
        navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
      }
    } catch (e) {
      Utils.showToast("${e.toString()}");
    }
  }

  void updateIsHomeTapped(bool value) {
    isHomeTapped = value;
    if (currentServiceSelection != null) {
      currentServiceSelection!.isHomeSelected = value;
    }
    notifyListeners();
  }

  String pickedHomeLocation = "";

  void updatePickedHomeLocation(String value) {
    pickedHomeLocation = value;
    pickHomeLocationError = "";
    if (currentServiceSelection != null) {
      currentServiceSelection!.homeLocation = value;
    }
    notifyListeners();
  }

  SelectionModel branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateProviderCategoryId(SelectionModel id) {
    branchSelectedCategoryId = id;
    getBranchServices(categoryId: branchSelectedCategoryId.selectedId);
    notifyListeners();
  }

  List<FilterListModel> branchesFilterOptions = [];

  List<ServiceModel> servicesInCurrentAppointment = [];
  ServiceModel? currentServiceSelection;

  void updateBranchServiceId(SelectionModel id) async {
    branchSelectedServiceId = id;
    currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId);

    notifyListeners();
  }

  void removeServiceInCurrentAppointment(int index) {
    int serviceId = servicesInCurrentAppointment.elementAt(index).serviceProviderServiceId ?? -1;
    allSelectedItemsInAppointments.removeWhere((element) => element.serviceProviderServiceId == serviceId);
    servicesInCurrentAppointment.removeAt(index);
    notifyListeners();
  }

  resetCategorySelectionBottomSheet() {
    selectedSubServicesCounter = 0;
    branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    isHomeTapped = false;
    branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    currentServiceSelection = null;
  }

  resetAfterBookingAppointment() {
    // allSelectedItemsInAppointments.clear();
    servicesInCurrentAppointment.clear();
    // serviceAppointmentScheduleList.clear();
  }

  List<EnumsModel> myAppointmentsEnum = [];

  Future<void> populateAppointmentsFilterList() async {
    if (appointmentsFilterOptions.isNotEmpty) return;

    myAppointmentsEnum = await commonRepo.getEnumTypeValues(enumTypeID: 13); // 13 is to get Appointments Filter Enums

    for (int i = 0; i < myAppointmentsEnum.length; i++) {
      appointmentsFilterOptions.add(FilterListModel(title: myAppointmentsEnum[i].enumValueStr, isSelected: false, id: myAppointmentsEnum[i].enumValue));
    }
    appointmentsFilterOptions.insert(0, FilterListModel(title: "All Appointments", isSelected: true, id: 0));

    // TODO: THIS SHOULD REMOVED AND ADDED IN THE ENUMS API
    appointmentsFilterOptions.add(FilterListModel(title: "Work In Progress", isSelected: false, id: 7));
    appointmentsFilterOptions.add(FilterListModel(title: "Visit Completed", isSelected: false, id: 8));
    notifyListeners();
  }

  applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum, bool isNeedCustomerFilter = false}) {
    // isNeedCustomerFilter IS ONLY FOR THE PROVIDER APP
    if (appointmentsFilterOptions.isEmpty) return;
    for (var value in appointmentsFilterOptions) {
      value.isSelected = false;
    }

    for (var element in appointmentsFilterOptions) {
      if (element.id == appointmentStatusEnum.getIdFromAppointmentStatusEnum()) {
        element.isSelected = true;
      }
    }
    // appointmentsFilterOptions[
    // appointmentStatusEnum.getIdFromAppointmentStatusEnum()]
    //     .isSelected = true;

    if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == 0) {
      myFilteredAppointments = myAppointments;
      if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers();
      notifyListeners();
      return;
    }

    myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList();
    if (isNeedCustomerFilter) findAppointmentsBasedOnCustomers();
    notifyListeners();
  }

  findAppointmentsBasedOnCustomers() {
    // Use a Set to ensure uniqueness of customerIDs
    Set<int> uniqueCustomerIDs = <int>{};

    // Extract unique customerIDs
    for (var item in myFilteredAppointments) {
      uniqueCustomerIDs.add(item.customerID ?? 0);
    }

    // Create a list of CustomerData instances
    myFilteredAppointments2 = uniqueCustomerIDs.map((id) {
      List<AppointmentListModel> list = myFilteredAppointments.where((item) => item.customerID == id).toList();
      AppointmentListModel model = list.first;
      model.customerAppointmentList = list;
      return model;
    }).toList();
    // customersAppointments = uniqueCustomerIDs.map((id) {
    //   List<AppointmentListModel> list = myFilteredAppointments
    //       .where((item) => item.customerID == id)
    //       .toList();
    //   var customerItem =
    //       myFilteredAppointments.firstWhere((item) => item.customerID == id);
    //
    //   return CustomerData(
    //     customerID: id,
    //     customerName: customerItem.customerName ?? "",
    //     appointmentList: list,
    //   );
    // }).toList();
  }

  // Future<void> getMyAppointments() async {
  //   setState(ViewState.busy);
  //
  //   myAppointments =
  //   await appointmentRepo.getMyAppointmentsForCustomersByFilters();
  //   myFilteredAppointments = myAppointments;
  //   myUpComingAppointments = myAppointments
  //       .where((element) =>
  //   element.appointmentStatusEnum == AppointmentStatusEnum.booked)
  //       .toList();
  //   applyFilterOnAppointmentsVM(
  //       appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
  //   if (myUpComingAppointments.isEmpty) {
  //     isShowEmptyMessage = true;
  //   }
  //   setState(ViewState.idle);
  //   notifyListeners();
  // }

  Future<void> getMyAppointments({bool isNeedToRebuild = false}) async {
    if (isNeedToRebuild) setState(ViewState.busy);

    myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters();
    // myFilteredAppointments = myAppointments;
    myUpComingAppointments =
        myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked || element.appointmentStatusEnum == AppointmentStatusEnum.confirmed).toList();
    setState(ViewState.idle);
    applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
    notifyListeners();
  }

  AppointmentSlots? appointmentSlots;

  Future<void> getAppointmentSlotsInfo({required Map<String, dynamic> map, required BuildContext context, bool isNeedToRebuild = false}) async {
    if (isNeedToRebuild) setState(ViewState.busy);
    try {
      MResponse genericRespModel = await appointmentRepo.getAppointmentSlots(map);
      if (genericRespModel.messageStatus == 1) {
        appointmentSlots = AppointmentSlots.fromJson(genericRespModel.data);
      } else {
        Utils.showToast(genericRespModel.message.toString());
      }
    } catch (e) {
      Utils.showToast(e.toString());
    }
  }

  Future<void> getMyAppointmentsForProvider(
    Map<String, dynamic> map,
  ) async {
    setState(ViewState.busy);
    myAppointments = await appointmentRepo.getMyAppointmentsForProvider(map);
    myFilteredAppointments = myAppointments;
    myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.confirmed).toList();
    applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments, isNeedCustomerFilter: true);
    setState(ViewState.idle);
  }

  updateAppointmentStatus(Map<String, dynamic> map, {bool isNeedToRebuild = false}) async {
    if (isNeedToRebuild) setState(ViewState.busy);
    try {
      MResponse genericRespModel = await appointmentRepo.updateAppointmentStatus(map);

      if (genericRespModel.messageStatus == 1) {
        Utils.showToast(LocaleKeys.appointmentStatusUpdated.tr());
      } else {
        Utils.showToast(genericRespModel.message.toString());
      }
    } catch (e) {
      Utils.showToast(e.toString());
    }
  }

  updateAppointmentPaymentStatus(Map<String, dynamic> map, {bool isNeedToRebuild = false}) async {
    if (isNeedToRebuild) setState(ViewState.busy);
    try {
      MResponse genericRespModel = await appointmentRepo.updateAppointmentPaymentStatus(map);

      if (genericRespModel.messageStatus == 1) {
        Utils.showToast(LocaleKeys.paymentStatusUpdated.tr());
      } else {
        Utils.showToast(genericRespModel.message.toString());
      }
    } catch (e) {
      Utils.showToast(e.toString());
    }
  }

  Future<MResponse> createMergeAppointment(Map<String, dynamic> map, {bool isNeedToRebuild = false}) async {
    if (isNeedToRebuild) setState(ViewState.busy);
    MResponse genericRespModel = await appointmentRepo.createMergeAppointment(map);

    return genericRespModel;
  }

  bool inNeedToEnableMergeButton = false;

  updateCheckBoxInMergeRequest(int currentIndex) {
    myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList![currentIndex].isSelected =
        !(myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList?[currentIndex].isSelected ?? false);

    int count = countSelected(myFilteredAppointments2[selectedAppointmentIndex].customerAppointmentList ?? []);
    if (count > 1)
      inNeedToEnableMergeButton = true;
    else
      inNeedToEnableMergeButton = false;
    notifyListeners();
  }

  int countSelected(List<AppointmentListModel> appointments) {
    return appointments.where((appointment) => appointment.isSelected == true).toList().length;
  }

  updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) {
    for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) {
      element.date!.isSelected = false;
    }

    serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.isSelected = true;
    serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex;
    final date = TimeSlotModel(
      date: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.date,
      slotId: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.slotId,
      isSelected: true,
      slot: "",
    );
    serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date);
    notifyListeners();
  }

  updateSelectedAppointmentSlotByDate({required int scheduleIndex, required int slotIndex}) {
    for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) {
      for (var element in element.availableSlots!) {
        element.isSelected = false;
      }
    }
    int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!;
    serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true;
    serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!;
    notifyListeners();
  }

  double amountToPayForAppointment = 0.0;
  double totalAmount = 0.0;

  List<ItemData> serviceItemsFromApi = [];

  ProviderProfileModel? providerProfileModel;

  int selectedSubServicesCounter = 0;

  onItemUpdateOrSelected(int index, bool selected, int itemId) {
    int serviceIndex = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!);
    // print("servicesInCurrentAppointment: ${servicesInCurrentAppointment.length}");
    // if (serviceIndex == -1) {
    //   return;
    // }

    serviceItemsFromApi[index].isUpdateOrSelected = selected;
    serviceItemsFromApi[index].isHomeSelected = isHomeTapped;
    if (selected) {
      selectedSubServicesCounter = selectedSubServicesCounter + 1;
      selectSubServicesError = "";
      currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]);
      allSelectedItemsInAppointments.add(serviceItemsFromApi[index]);
      for (var element in allSelectedItemsInAppointments) {
        if (!ifItemAlreadySelected(element.id!)) {
          servicesInCurrentAppointment[serviceIndex].serviceItems!.add(serviceItemsFromApi[index]);
          servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice =
              servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice + double.parse((serviceItemsFromApi[index].price) ?? "0.0");
        }
      }
    }
    if (!selected) {
      selectedSubServicesCounter = selectedSubServicesCounter - 1;
      currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId);
      allSelectedItemsInAppointments.removeWhere((element) => element.id == itemId);
      servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice =
          servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice - double.parse((serviceItemsFromApi[index].price) ?? "0.0");
      servicesInCurrentAppointment[serviceIndex].serviceItems!.removeWhere((element) => element.id == itemId);
    }
    notifyListeners();
  }

  Future<void> applyFilterOnBranches({required int index}) async {
    if (branchesFilterOptions.isEmpty) return;
    for (var value in branchesFilterOptions) {
      value.isSelected = false;
    }
    branchesFilterOptions[index].isSelected = true;

    await getBranchesBasedOnCategoryFilters(categoryId: branchesFilterOptions[index].id);
    notifyListeners();
  }

  Future<List<ItemData>> getServiceItems(int serviceId) async {
    serviceItemsFromApi.clear();
    serviceItemsFromApi = await branchRepo.getServiceItems(serviceId);
    for (var item in serviceItemsFromApi) {
      if (ifItemAlreadySelected(item.id!)) {
        item.isUpdateOrSelected = true;
      }
    }
    setState(ViewState.idle);
    return serviceItemsFromApi;
  }

  String pickHomeLocationError = "";
  String selectSubServicesError = "";

  SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updatePickHomeLocationError(String value) {
    pickHomeLocationError = value;
    // notifyListeners();
  }

  bool isServiceSelectionValidated() {
    if (branchSelectedServiceId.selectedId == -1) {
      return false;
    }

    if (isHomeTapped) {
      if (pickedHomeLocation == "") {
        updatePickHomeLocationError(GlobalConsts.homeLocationEmptyError);
        return false;
      }
    }
    return true;
  }

  bool validateItemsSelection() {
    for (var value in serviceItemsFromApi) {
      if (value.isUpdateOrSelected!) {
        return true;
      }
    }
    selectSubServicesError = LocaleKeys.selectOneSubService.tr();
    notifyListeners();
    return false;
  }

  String getTotalPrice(List<ServiceModel> serviceItems) {
    var totalPrice = 0.0;
    for (var element in serviceItems) {
      totalPrice = totalPrice + (element.currentTotalServicePrice);
    }
    return totalPrice.toString();
  }

  void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) {
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      enableDrag: true,
      builder: (BuildContext context) {
        return const AppointmentServicePickBottomSheet();
      },
    );
  }

  void priceBreakDownClicked(BuildContext context, ServiceModel selectedService) {
    showModalBottomSheet(
        context: context,
        isScrollControlled: true,
        enableDrag: true,
        builder: (BuildContext context) {
          double totalKms = 15.3;
          return InfoBottomSheet(
              title: LocaleKeys.chargesBreakdown.tr().toText(fontSize: 24, isBold: true),
              description: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  LocaleKeys.services.tr().toText(fontSize: 16, isBold: true),
                  Column(
                    children: List.generate(
                      selectedService.serviceItems!.length,
                      (index) => Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          "${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
                          "${selectedService.serviceItems![index].price} SAR".toText(fontSize: 12, isBold: true),
                        ],
                      ),
                    ),
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: [
                      "${selectedService.currentTotalServicePrice} SAR".toText(fontSize: 16, isBold: true),
                    ],
                  ),
                  if (selectedService.isHomeSelected) ...[
                    20.height,
                    LocaleKeys.homeLocation.tr().toText(fontSize: 16, isBold: true),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        "${totalKms}km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
                        "${selectedService.rangePricePerKm} x $totalKms".toText(fontSize: 12, isBold: true),
                      ],
                    ),
                    8.height,
                    Row(
                      mainAxisAlignment: MainAxisAlignment.end,
                      children: [
                        "${selectedService.rangePricePerKm ?? 0 * totalKms} SAR".toText(fontSize: 16, isBold: true),
                      ],
                    ),
                  ],
                  30.height,
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      LocaleKeys.totalAmount.tr().toText(fontSize: 16, isBold: true),
                      Row(
                        crossAxisAlignment: CrossAxisAlignment.end,
                        children: [
                          (selectedService.isHomeSelected
                                  ? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}"
                                  : "${selectedService.currentTotalServicePrice}")
                              .toText(fontSize: 29, isBold: true),
                          2.width,
                          LocaleKeys.sar.tr().toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
                        ],
                      )
                    ],
                  ),
                  30.height,
                ],
              ));
        });
  }

  void onReviewButtonPressed(BuildContext context) {
    bool isValidated = false;

    for (int i = 0; i < serviceAppointmentScheduleList.length; i++) {
      final schedule = serviceAppointmentScheduleList[i];
      if (schedule.selectedCustomTimeDateSlotModel == null) {
        isValidated = false;
        break;
      }
      if (schedule.selectedCustomTimeDateSlotModel!.date == null || !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) {
        isValidated = false;
        break;
      } else {
        if (schedule.selectedCustomTimeDateSlotModel!.availableSlots == null) {
          isValidated = false;
          break;
        } else {
          TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected);
          if (slot.date.isNotEmpty) {
            isValidated = true;
            break;
          }
        }
      }
    }
    if (!isValidated) {
      Utils.showToast(LocaleKeys.selectAppointmentTime.tr());
      return;
    }
    navigateWithName(context, AppRoutes.reviewAppointmentView);
  }

  void onServicesNextPressed(BuildContext context) async {
    Utils.showLoading(context);

    List<String> serviceItemIdsForHome = [];
    List<String> serviceItemIdsForWorkshop = [];
    for (var serviceItem in allSelectedItemsInAppointments) {
      if (serviceItem.isHomeSelected!) {
        serviceItemIdsForHome.add(serviceItem.id!.toString());
      } else {
        serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
      }
    }

    serviceAppointmentScheduleList = await appointmentRepo.mergeServiceIntoAvailableSchedules(
      serviceItemIdsForHome: serviceItemIdsForHome,
      serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
    );

    if (serviceAppointmentScheduleList.isEmpty) {
      Utils.hideLoading(context);
      Utils.showToast(LocaleKeys.noAppointmentAvailable.tr());
      return;
    }
    totalAmount = 0.0;
    amountToPayForAppointment = 0.0;
    for (var schedule in serviceAppointmentScheduleList) {
      amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0);
      totalAmount = totalAmount + (schedule.amountTotal ?? 0.0);
    }
    Utils.hideLoading(context);

    navigateWithName(context, AppRoutes.bookAppointmenSchedulesView, arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 1, appointmentId: 0)); // 1 For Creating an Appointment

    notifyListeners();
  }

  Future<void> onRescheduleAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
    Utils.showLoading(context);

    List<String> serviceItemIdsForHome = [];
    List<String> serviceItemIdsForWorkshop = [];
    for (var service in appointmentListModel.appointmentServicesList!) {
      for (var serviceItem in service.serviceItems!) {
        serviceItemIdsForWorkshop.add(serviceItem.id!.toString());

        // if (serviceItem.isHomeSelected ?? false) {
        //   serviceItemIdsForHome.add(serviceItem.id!.toString());
        // } else {
        //   serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
        // }
      }
    }

    serviceAppointmentScheduleList = await appointmentRepo.mergeServiceIntoAvailableSchedules(
      serviceItemIdsForHome: serviceItemIdsForHome,
      serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
    );

    if (serviceAppointmentScheduleList.isEmpty) {
      Utils.hideLoading(context);
      Utils.showToast(LocaleKeys.noAppointmentAvailable.tr());
      return;
    }
    Utils.hideLoading(context);

    navigateWithName(
      context,
      AppRoutes.bookAppointmenSchedulesView,
      arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 2, appointmentId: appointmentListModel.id ?? 0),
    ); // 2 For Rescheduling an Appointment

    notifyListeners();
  }

  Future<void> onRescheduleAppointmentConfirmPressed({required BuildContext context, required int appointmentId, required int selectedSlotId}) async {
    Utils.showLoading(context);
    try {
      GenericRespModel genericRespModel = await appointmentRepo.cancelOrRescheduleServiceAppointment(
        serviceAppointmentID: appointmentId,
        serviceSlotID: selectedSlotId,
        appointmentScheduleAction: 1, // 1 for Reschedule and 2 for Cancel
      );

      if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
        Utils.hideLoading(context);
        Utils.showToast("${genericRespModel.message.toString()}");
        return;
      }
      if (genericRespModel.messageStatus == 1) {
        context.read<DashboardVmCustomer>().onNavbarTapped(1);
        applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
        Utils.showToast("${genericRespModel.message.toString()}");
        getMyAppointments();
        Utils.hideLoading(context);
        navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
      }
    } catch (e) {
      Utils.showToast("${e.toString()}");
    }
  }

  // BRANCHES RELATED

  List<BranchDetailModel> nearbyBranches = [];
  List<BranchDetailModel> myRecentBranches = [];
  BranchDetailModel? selectedBranchModel;

  List<ServiceModel> branchServices = [];

  // populateBranchesFilterList() {
  //   branchesFilterOptions.clear(); // TODO: THIS SHOULD BE DYNAMIC AND FILTERS SHOULD COME FORM API
  //   branchesFilterOptions = [
  //     FilterListModel(title: "All Branches", isSelected: true, id: 0),
  //     FilterListModel(title: "Maintenance", isSelected: false, id: 1),
  //     FilterListModel(title: "Oil Service", isSelected: false, id: 2),
  //     FilterListModel(title: "Accessories", isSelected: false, id: 3),
  //     FilterListModel(title: "Tire Service", isSelected: false, id: 4),
  //     FilterListModel(title: "Dent and Paint", isSelected: false, id: 5),
  //   ];
  //   notifyListeners();
  // }

  Future<void> populateBranchesFilterList() async {
    if (branchesFilterOptions.isNotEmpty) return;
    branchesFilterOptions.clear();
    setOnlyState(ViewState.busy);
    Category category = await branchRepo.fetchBranchCategory();
    category.data?.forEach((element) {
      branchesFilterOptions.add(FilterListModel(id: element.id ?? 0, isSelected: false, title: element.categoryName ?? "N/A"));
    });
    branchesFilterOptions.insert(0, FilterListModel(id: 0, isSelected: true, title: "All Branches"));
    notifyListeners();
    setState(ViewState.idle);
  }

  Future<void> getAllNearBranches({bool isNeedToRebuild = false, bool isFromRefresh = false}) async {
    nearbyBranches.clear();
    if (isNeedToRebuild) setState(ViewState.busy);

    if (isFromRefresh) {
      var selectedBranch = branchesFilterOptions.firstWhere((element) => element.isSelected);
      nearbyBranches = await branchRepo.getBranchesByFilters(categoryIdsList: [selectedBranch.id]);
      setState(ViewState.idle);
      return;
    }
    nearbyBranches = await branchRepo.getAllNearBranchAndServices();
    setState(ViewState.idle);
  }

  Future<void> getMyRecentBranches({bool isNeedToRebuild = false}) async {
    myRecentBranches.clear();
    if (isNeedToRebuild) setState(ViewState.busy);
    myRecentBranches = await branchRepo.getAllNearBranchAndServices();
    setState(ViewState.idle);
  }

  void getBranchCategories() async {
    for (var value in selectedBranchModel!.branchServices!) {
      if (!isCategoryAlreadyPresent(value.categoryId!)) {
        branchCategories.add(DropValue(value.categoryId!, value.categoryName!, ""));
      }
    }
    notifyListeners();
  }

  getBranchServices({required int categoryId}) async {
    branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    isHomeTapped = false;
    pickedHomeLocation = "";
    pickHomeLocationError = "";
    if (categoryId != -1) {
      isFetchingServices = true;
      branchServices = getFilteredBranchServices(categoryId: categoryId);
      isFetchingServices = false;
      notifyListeners();
    }
  }

  List<ServiceModel> getFilteredBranchServices({required int categoryId}) {
    List<ServiceModel> filteredServices = selectedBranchModel!.branchServices!.where((element) => element.categoryId == categoryId).toList();
    return filteredServices;
  }

  getBranchAndServices(int providerId) async {
    providerProfileModel = null;
    providerProfileModel = await branchRepo.getBranchAndServicesByProviderId(providerId);
    setState(ViewState.idle);
  }

  bool isCategoryAlreadyPresent(int id) {
    final contain = branchCategories.where((element) => element.id == id);
    if (contain.isEmpty) {
      return false;
    }
    return true;
  }

  updateSelectedBranch(BranchDetailModel branchDetailModel) {
    selectedBranchModel = branchDetailModel;
    getBranchCategories();
    notifyListeners();
  }

  int branchFiltersCounter = 0;

  updateBranchFiltersCounter(int value) {
    branchFiltersCounter = value;
    notifyListeners();
  }

  double branchFilterCurrentDistance = 25.0;

  updateBranchFilterCurrentDistance(double value) {
    branchFilterCurrentDistance = value;
    notifyListeners();
  }

  // Provider Filter
  List<DropValue> branchFilterProviderSearchHistory = [];

  void removeBranchFilterProviderSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      branchFilterProviderSearchHistory.clear();
      notifyListeners();
      return;
    }
    branchFilterProviderSearchHistory.removeAt(index);
    if (branchFilterProviderSearchHistory.isEmpty) {
      updateBranchFiltersCounter(branchFiltersCounter - 1);
      // branchFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    }
    notifyListeners();
  }

  void addBranchFilterProviderSearchHistory({required DropValue value}) {
    if (branchFilterProviderSearchHistory.isEmpty) {
      updateBranchFiltersCounter(branchFiltersCounter + 1);
    }
    branchFilterProviderSearchHistory.add(value);
    notifyListeners();
  }

  SelectionModel branchFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateBranchFilterSelectedProviderId(SelectionModel id, {bool isForSearch = false}) async {
    if (isForSearch) {
      DropValue providerDrop = providersDropList.firstWhere((element) => element.id == id.selectedId);
      if (!ifAlreadyExist(list: branchFilterProviderSearchHistory, value: providerDrop)) {
        addBranchFilterProviderSearchHistory(value: providerDrop);
      }
    }

    branchFilterSelectedProviderId = id;
    notifyListeners();
  }

  // Category Filter
  List<DropValue> branchFilterCategorySearchHistory = [];

  void removeBranchFilterCategorySearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      branchFilterCategorySearchHistory.clear();
      notifyListeners();
      return;
    }
    branchFilterCategorySearchHistory.removeAt(index);
    if (branchFilterCategorySearchHistory.isEmpty) {
      updateBranchFiltersCounter(branchFiltersCounter - 1);
      // branchFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    }
    notifyListeners();
  }

  void addBranchFilterCategorySearchHistory({required DropValue value}) {
    if (branchFilterCategorySearchHistory.isEmpty) {
      updateBranchFiltersCounter(branchFiltersCounter + 1);
    }
    branchFilterCategorySearchHistory.add(value);
    notifyListeners();
  }

  SelectionModel branchFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateBranchFilterSelectedCategoryId(SelectionModel id, {bool isForSearch = false}) async {
    if (isForSearch) {
      DropValue categoryDrop = categoryDropList.firstWhere((element) => element.id == id.selectedId);
      if (!ifAlreadyExist(list: branchFilterCategorySearchHistory, value: categoryDrop)) {
        addBranchFilterCategorySearchHistory(value: categoryDrop);
      }
    }

    branchFilterSelectedCategoryId = id;
    notifyListeners();
  }

  // Services Filter
  List<DropValue> branchFilterServicesSearchHistory = [];

  void removeBranchFilterServicesSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      branchFilterServicesSearchHistory.clear();
      notifyListeners();
      return;
    }
    branchFilterServicesSearchHistory.removeAt(index);
    if (branchFilterServicesSearchHistory.isEmpty) {
      updateBranchFiltersCounter(branchFiltersCounter - 1);
      // branchFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    }
    notifyListeners();
  }

  void addBranchFilterServicesSearchHistory({required DropValue value}) {
    if (branchFilterServicesSearchHistory.isEmpty) {
      updateBranchFiltersCounter(branchFiltersCounter + 1);
    }
    branchFilterServicesSearchHistory.add(value);
    notifyListeners();
  }

  SelectionModel branchFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateBranchFilterSelectedServiceId(SelectionModel id, {bool isForSearch = false}) async {
    if (isForSearch) {
      DropValue serviceDrop = servicesDropList.firstWhere((element) => element.id == id.selectedId);
      if (!ifAlreadyExist(list: branchFilterServicesSearchHistory, value: serviceDrop)) {
        addBranchFilterServicesSearchHistory(value: serviceDrop);
      }
      notifyListeners();
      return;
    }

    branchFilterSelectedServiceId = id;
    notifyListeners();
  }

  ifAlreadyExist({required List<DropValue> list, required DropValue value}) {
    int index = list.indexWhere((element) {
      return element.id == value.id;
    });

    if (index != -1) {
      return true;
    }

    return false;
  }

  // Rating filter

  double branchFilterByRating = 4.0;

  updateBranchFilterByRating(double value) {
    branchFilterByRating = value;
    notifyListeners();
  }

  List<DropValue> categoryDropList = [];
  List<DropValue> servicesDropList = [];
  List<DropValue> providersDropList = [];

  Future<void> fetchAllProviders() async {
    if (providersDropList.isNotEmpty) return;

    providersDropList.clear();
    setOnlyState(ViewState.busy);
    List<ProviderBasicDataModel> providers = await branchRepo.getAllProvidersWitheBasicData();
    for (var element in providers) {
      providersDropList.add(
        DropValue(element.id ?? 0, element.providerName ?? "N/A", ""),
      );
    }
    setState(ViewState.idle);
  }

  Future<void> fetchAllCategories(String countryCode) async {
    if (categoryDropList.isNotEmpty) return;
    categoryDropList.clear();
    setOnlyState(ViewState.busy);
    Category category = await branchRepo.fetchBranchCategory();
    category.data?.forEach((element) {
      categoryDropList.add(
        DropValue(
            element.id ?? 0,
            ((element.categoryName!.isEmpty
                    ? "N/A"
                    : countryCode == "SA"
                        ? element.categoryNameN
                        : element.categoryName) ??
                "N/A"),
            ""),
      );
    });
    setState(ViewState.idle);
  }

  Future<void> fetchAllServices() async {
    if (servicesDropList.isNotEmpty) return;
    servicesDropList.clear();
    setState(ViewState.busy);
    Services services = await branchRepo.fetchServicesByCategoryId(serviceCategoryId: -1); // to get all services

    for (var element in services.data!) {
      servicesDropList.add(
        DropValue(
          element.id ?? 0,
          element.description ?? "N/A",
          "",
        ),
      );
    }
    setState(ViewState.idle);
  }

  Future<void> populateDataForBranchesFilter() async {
    await fetchAllProviders(); // saudi arabia
    await fetchAllCategories("SA"); // saudi arabia
    await fetchAllServices(); // saudi arabia
    updateBranchFilterCurrentDistance(25.0);
  }

  void clearBranchFilters() {
    branchFilterServicesSearchHistory.clear();
    branchFilterCategorySearchHistory.clear();
    branchFilterProviderSearchHistory.clear();
    branchFilterByRating = 4.0;
    branchFilterCurrentDistance = 25.0;
    branchFiltersCounter = 0;
    clearBranchFilterSelections();
    notifyListeners();
  }

  void clearBranchFilterSelections() {
    branchFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    branchFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    branchFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
  }

  Future<void> getBranchesBasedOnFilters() async {
    nearbyBranches.clear();
    setState(ViewState.busy);
    List<int> providersIdsList = [];
    if (branchFilterProviderSearchHistory.isNotEmpty) {
      for (var element in branchFilterProviderSearchHistory) {
        providersIdsList.add(element.id);
      }
    }
    List<int> categoryIdsList = [];
    if (branchFilterCategorySearchHistory.isNotEmpty) {
      for (var element in branchFilterCategorySearchHistory) {
        categoryIdsList.add(element.id);
      }
    }
    List<int> servicesIdsList = [];
    if (branchFilterServicesSearchHistory.isNotEmpty) {
      for (var element in branchFilterServicesSearchHistory) {
        servicesIdsList.add(element.id);
      }
    }

    nearbyBranches = await branchRepo.getBranchesByFilters(
      providerIdsList: providersIdsList.isNotEmpty ? providersIdsList : null,
      categoryIdsList: categoryIdsList.isNotEmpty ? categoryIdsList : null,
      serviceIdsList: servicesIdsList.isNotEmpty ? servicesIdsList : null,
      distanceKm: branchFilterCurrentDistance.toInt(),
      rating: branchFilterByRating.toInt(),
      latitude: 24.694969,
      longitude: 46.724129,
    );
    setState(ViewState.idle);
  }

  Future<void> getBranchesBasedOnCategoryFilters({required int categoryId}) async {
    if (categoryId == 0) {
      await getAllNearBranches();
      return;
    }
    setState(ViewState.busy);
    nearbyBranches.clear();
    nearbyBranches = await branchRepo.getBranchesByFilters(categoryIdsList: [categoryId]);
    setState(ViewState.idle);
  }

  // Appointments Filter Screen

  List<DropValue> branchesDropList = [];

  Future<void> fetchAllBranchesBySelectedProviderId({required List<int> providersIdsList}) async {
    branchesDropList.clear();
    setOnlyState(ViewState.busy);
    List<BranchDetailModel> providers = await branchRepo.getBranchesByFilters(providerIdsList: providersIdsList);
    for (var element in providers) {
      branchesDropList.add(DropValue(element.id ?? 0, element.branchName ?? "N/A", ""));
    }
    setState(ViewState.idle);

    log("branchesDropList: ${branchesDropList.length}");
  }

  Future<void> populateDataForAppointmentsFilter() async {
    await fetchAllProviders(); // saudi arabia
    await fetchAllCategories("SA"); // saudi arabia
    await fetchAllServices(); // saudi arabia
  }

  int appointmentFiltersCounter = 0;

  updateAppointmentFiltersCounter(int value) {
    appointmentFiltersCounter = value;
    notifyListeners();
  }

  // Provider Filter For Appointments
  List<DropValue> appointmentFilterProviderSearchHistory = [];

  void removeAppointmentFilterProviderSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      appointmentFilterProviderSearchHistory.clear();
      notifyListeners();
      return;
    }
    appointmentFilterProviderSearchHistory.removeAt(index);
    if (appointmentFilterProviderSearchHistory.isNotEmpty) {
      List<int> providerIdsSelected = [];
      for (var element in appointmentFilterProviderSearchHistory) {
        providerIdsSelected.add(element.id);
      }
      fetchAllBranchesBySelectedProviderId(providersIdsList: providerIdsSelected);
    }

    if (appointmentFilterProviderSearchHistory.isEmpty) {
      updateAppointmentFiltersCounter(appointmentFiltersCounter - 1);
      // appointmentFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    }
    notifyListeners();
  }

  void addAppointmentFilterProviderSearchHistory({required DropValue value}) {
    if (appointmentFilterProviderSearchHistory.isEmpty) {
      updateAppointmentFiltersCounter(appointmentFiltersCounter + 1);
    }
    List<int> providerIdsSelected = [];
    for (var element in appointmentFilterProviderSearchHistory) {
      providerIdsSelected.add(element.id);
    }
    fetchAllBranchesBySelectedProviderId(providersIdsList: providerIdsSelected);
    appointmentFilterProviderSearchHistory.add(value);
    notifyListeners();
  }

  SelectionModel appointmentFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateAppointmentFilterSelectedProviderId(SelectionModel id, {bool isForSearch = false}) async {
    if (isForSearch) {
      DropValue providerDrop = providersDropList.firstWhere((element) => element.id == id.selectedId);
      if (!ifAlreadyExist(list: appointmentFilterProviderSearchHistory, value: providerDrop)) {
        addAppointmentFilterProviderSearchHistory(value: providerDrop);
      }
    }
    // appointmentFilterSelectedProviderId = id;
    notifyListeners();
  }

  // Branches Filter For Appointments

  List<DropValue> appointmentFilterBranchSearchHistory = [];

  void removeAppointmentFilterBranchSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      appointmentFilterBranchSearchHistory.clear();
      notifyListeners();
      return;
    }
    appointmentFilterBranchSearchHistory.removeAt(index);
    if (appointmentFilterBranchSearchHistory.isEmpty) {
      updateAppointmentFiltersCounter(appointmentFiltersCounter - 1);
      // appointmentFilterSelectedBranchId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    }
    notifyListeners();
  }

  void addAppointmentFilterBranchSearchHistory({required DropValue value}) {
    if (appointmentFilterBranchSearchHistory.isEmpty) {
      updateAppointmentFiltersCounter(appointmentFiltersCounter + 1);
    }
    appointmentFilterBranchSearchHistory.add(value);
    notifyListeners();
  }

  SelectionModel appointmentFilterSelectedBranchId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateAppointmentFilterSelectedBranchId(SelectionModel id, {bool isForSearch = false}) async {
    if (isForSearch) {
      DropValue branchesDrop = branchesDropList.firstWhere((element) => element.id == id.selectedId);
      if (!ifAlreadyExist(list: appointmentFilterBranchSearchHistory, value: branchesDrop)) {
        addAppointmentFilterBranchSearchHistory(value: branchesDrop);
      }
    }
    // appointmentFilterSelectedBranchId = id;
    notifyListeners();
  }

  // Category Filter For Appointments

  List<DropValue> appointmentFilterCategorySearchHistory = [];

  void removeAppointmentFilterCategorySearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      appointmentFilterCategorySearchHistory.clear();
      notifyListeners();
      return;
    }
    appointmentFilterCategorySearchHistory.removeAt(index);
    if (appointmentFilterCategorySearchHistory.isEmpty) {
      updateAppointmentFiltersCounter(appointmentFiltersCounter - 1);
      // appointmentFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    }
    notifyListeners();
  }

  void addAppointmentFilterCategorySearchHistory({required DropValue value}) {
    if (appointmentFilterCategorySearchHistory.isEmpty) {
      updateAppointmentFiltersCounter(appointmentFiltersCounter + 1);
    }
    appointmentFilterCategorySearchHistory.add(value);
    notifyListeners();
  }

  SelectionModel appointmentFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateAppointmentFilterSelectedCategoryId(SelectionModel id, {bool isForSearch = false}) async {
    if (isForSearch) {
      DropValue categoryDrop = categoryDropList.firstWhere((element) => element.id == id.selectedId);
      if (!ifAlreadyExist(list: appointmentFilterCategorySearchHistory, value: categoryDrop)) {
        addAppointmentFilterCategorySearchHistory(value: categoryDrop);
      }
    }
    // appointmentFilterSelectedCategoryId = id;
    notifyListeners();
  }

  List<DropValue> appointmentFilterServicesSearchHistory = [];

  void removeAppointmentFilterServicesSearchHistory({bool isClear = false, required int index}) {
    if (isClear) {
      appointmentFilterServicesSearchHistory.clear();
      notifyListeners();
      return;
    }
    appointmentFilterServicesSearchHistory.removeAt(index);
    if (appointmentFilterServicesSearchHistory.isEmpty) {
      updateAppointmentFiltersCounter(appointmentFiltersCounter - 1);
      // appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    }
    notifyListeners();
  }

  void addAppointmentFilterServicesSearchHistory({required DropValue value}) {
    if (appointmentFilterServicesSearchHistory.isEmpty) {
      updateAppointmentFiltersCounter(appointmentFiltersCounter + 1);
    }
    appointmentFilterServicesSearchHistory.add(value);
    notifyListeners();
  }

  SelectionModel appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");

  void updateAppointmentFilterSelectedServiceId(SelectionModel id, {bool isForSearch = false}) async {
    if (isForSearch) {
      DropValue servicesDrop = servicesDropList.firstWhere((element) => element.id == id.selectedId);
      if (!ifAlreadyExist(list: appointmentFilterServicesSearchHistory, value: servicesDrop)) {
        addAppointmentFilterServicesSearchHistory(value: servicesDrop);
      }
    }
    // appointmentFilterSelectedServiceId = id;
    notifyListeners();
  }

  void clearAppointmentFilterSelections() {
    appointmentFilterSelectedProviderId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    appointmentFilterSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    appointmentFilterSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
    appointmentFilterSelectedBranchId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
  }

  void clearAppointmentFilters() {
    appointmentFilterServicesSearchHistory.clear();
    appointmentFilterCategorySearchHistory.clear();
    appointmentFilterProviderSearchHistory.clear();
    appointmentFilterBranchSearchHistory.clear();
    appointmentFiltersCounter = 0;
    clearAppointmentFilterSelections();
    getMyAppointments();
    notifyListeners();
  }

  Future<void> getAppointmentsBasedOnFilters() async {
    setState(ViewState.busy);
    List<String> providersIdsList = [];
    if (appointmentFilterProviderSearchHistory.isNotEmpty) {
      for (var element in appointmentFilterProviderSearchHistory) {
        providersIdsList.add(element.id.toString());
      }
    }
    List<String> categoryIdsList = [];
    if (appointmentFilterCategorySearchHistory.isNotEmpty) {
      for (var element in appointmentFilterCategorySearchHistory) {
        categoryIdsList.add(element.id.toString());
      }
    }
    List<String> servicesIdsList = [];
    if (appointmentFilterServicesSearchHistory.isNotEmpty) {
      for (var element in appointmentFilterServicesSearchHistory) {
        servicesIdsList.add(element.id.toString());
      }
    }
    List<String> branchesIdsList = [];
    if (appointmentFilterBranchSearchHistory.isNotEmpty) {
      for (var element in appointmentFilterBranchSearchHistory) {
        branchesIdsList.add(element.id.toString());
      }
    }

    myAppointments = await appointmentRepo.getMyAppointmentsForCustomersByFilters(
      providerIdsList: providersIdsList,
      categoryIdsList: categoryIdsList,
      serviceIdsList: servicesIdsList,
      branchIdsList: branchesIdsList,
    );
    applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
    setState(ViewState.idle);
  }
}
