import 'dart:async';

import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' as GMSMapServices;
import 'package:hmg_patient_app_new/core/app_assets.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/location_util.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/authentication/authentication_view_model.dart';
import 'package:hmg_patient_app_new/features/authentication/models/resp_models/authenticated_user_resp_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_repo.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/AmbulanceCallingPlace.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/OrderDisplay.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/PatientER_RC.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/request_model/RRTRequestModel.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/AmbulanceRequestOrdersModel.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/EROnlineCheckInPaymentDetailsResponse.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/PatientERTransportationMethod.dart'
    show PatientERTransportationMethod;
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/ProjectAvgERWaitingTime.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/RRTServiceData.dart';
import 'package:hmg_patient_app_new/features/emergency_services/models/resp_model/rrt_procedures_response_model.dart';
import 'package:hmg_patient_app_new/features/location/PlaceDetails.dart' show PlaceDetails;
import 'package:hmg_patient_app_new/features/location/PlacePrediction.dart';
import 'package:hmg_patient_app_new/features/location/location_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/facility_selection.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/rrt_request_type_select.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/RRT/terms_and_condition.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/call_ambulance_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/requesting_services_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/call_ambulance/tracking_screen.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_home.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/er_online_checkin/er_online_checkin_payment_details_page.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/nearest_er_page.dart';
import 'package:hmg_patient_app_new/routes/app_routes.dart' show AppRoutes;
import 'package:hmg_patient_app_new/services/dialog_service.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/expandable_bottom_sheet/model/BottomSheetType.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:hmg_patient_app_new/widgets/map/map_utility_screen.dart';
import 'package:hmg_patient_app_new/widgets/order_tracking/order_tracking_state.dart';
import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart';
import 'package:huawei_map/huawei_map.dart' as HMSCameraServices;
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';

import '../location/GeocodeResponse.dart';
import 'models/ambulance_direction.dart';

class EmergencyServicesViewModel extends ChangeNotifier {
  EmergencyServicesRepo emergencyServicesRepo;
  MyAppointmentsRepo appointmentRepo;
  ErrorHandlerService errorHandlerService;
  DialogService dialogService;

  Completer<GMSMapServices.GoogleMapController>? gmsController;
  Completer<HMSCameraServices.HuaweiMapController>? hmsController;

  final NavigationService navServices;
  final LocationUtils? locationUtils;
  final AppState appState;
  TextEditingController searchController = TextEditingController();

  //loading variables
  bool isERListLoading = false;
  bool isTransportationOptionsLoading = false;

  List<ProjectAvgERWaitingTime> nearestERList = [];
  List<ProjectAvgERWaitingTime> nearestERFilteredList = [];

  List<HospitalsModel>? hospitalList;
  List<HospitalsModel>? hmgHospitalList;
  List<HospitalsModel>? hmcHospitalList;
  List<HospitalsModel>? displayList;
  HospitalsModel? selectedHospital;
  FacilitySelection selectedFacility = FacilitySelection.ALL;
  int hmgCount = 0;
  int hmcCount = 0;
  bool pickupFromInsideTheLocation = true;
  List<PatientAppointmentHistoryResponseModel>? appointments;
  List<AmbulanceRequestOrdersModel>? ambulanceOrders = [];

  //ambulance selection data section
  List<PatientERTransportationMethod> transportationOptions = [];
  PatientERTransportationMethod? selectedTransportOption;
  AmbulanceCallingPlace callingPlace = AmbulanceCallingPlace.FROM_HOSPITAL;
  AmbulanceDirection ambulanceDirection = AmbulanceDirection.ONE_WAY;

  bool patientHasAdvanceERBalance = false;
  bool isERBookAppointment = false;
  late EROnlineCheckInPaymentDetailsResponse erOnlineCheckInPaymentDetailsResponse;

  BottomSheetType bottomSheetType = BottomSheetType.FIXED;

  ///RRT request data
  List<RRTProceduresResponseModel> RRTProceduresList = [];
  RRTProceduresResponseModel? selectedRRTProcedure;
  bool agreedToTermsAndCondition = false;
  RRTServiceData? ordersRRT;
  TextEditingController rrtNotes = TextEditingController();

  List allOrders = [];
  List orderDisplayList = [];
  bool historyLoading = false;
  OrderDislpay currentlyDisplayedOrder = OrderDislpay.ALL;

  bool isAdvanceERBalanceNeedToBeLoaded = true;

  setIsAdvanceERBalanceNeedToBeLoaded(bool value) {
    isAdvanceERBalanceNeedToBeLoaded = value;
    notifyListeners();
  }

  setSelectedRRTProcedure(RRTProceduresResponseModel procedure) {
    selectedRRTProcedure = procedure;
    notifyListeners();
  }

  get isGMSAvailable {
    return appState.isGMSAvailable;
  }

  EmergencyServicesViewModel({
    required this.emergencyServicesRepo,
    required this.errorHandlerService,
    required this.navServices,
    required this.locationUtils,
    required this.appState,
    required this.appointmentRepo,
    required this.dialogService,
  });

  void setIsERBookAppointment(bool value) {
    isERBookAppointment = value;
    notifyListeners();
  }

  bool get isArabic => appState.isArabic();

  bool haveAnAppointment = false;

  PatientAppointmentHistoryResponseModel? appointment;

  bool isMyAppointmentsLoading = false;

  String? termsAndConditions;

  Future<void> getRRTProcedures({Function(dynamic)? onSuccess, Function(String)? onError}) async {
    print("the app state is ${appState.isAuthenticated}");
    if (!appState.isAuthenticated) {
      dialogService.showErrorBottomSheet(
          message: LocaleKeys.loginToUseService.tr(),
          onOkPressed: () {
            navServices.pop();
            getIt<AuthenticationViewModel>().onLoginPressed();
          });
      return;
    }

    RRTProceduresList.clear();
    notifyListeners();

    final result = await emergencyServicesRepo.getRRTProcedures(appState.getLanguageID());

    result.fold(
      (failure) async => await errorHandlerService.handleError(failure: failure),
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
          // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
        } else if (apiResponse.messageStatus == 1) {
          RRTProceduresList = apiResponse.data!;
          selectedRRTProcedure = RRTProceduresList.first;
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse);
          }
        }
      },
    );
  }

  void navigateToNearestERPage() {
    locationUtils!.getLocation(
        isShowConfirmDialog: true,
        onSuccess: (position) {
          navServices.push(
            CustomPageRoute(
              page: NearestErPage(),
            ),
          );
          getNearestER();
        });
  }

  void filterErList(String query) {
    if (query.isEmpty) {
      nearestERFilteredList = nearestERList;
    } else {
      nearestERFilteredList =
          nearestERList.where((er) => er.projectName != null && er.projectName!.toLowerCase().contains(query.toLowerCase())).toList();
    }
    notifyListeners();
  }

  // Open directions (navigation) from current location to destination.
  Future<void> openDirections({
    required double destLat,
    required double destLng,
    String? travelMode, // driving, walking, bicycling, transit
  }) async {
    // Try Google Maps app navigation intent (android/iOS)
    final modeParam = travelMode == null ? 'driving' : travelMode;
    final googleNavUri = Uri.parse('google.navigation:q=$destLat,$destLng&mode=${modeParam.substring(0, 1)}'); // mode: d/w/b/t by scheme
    final universalUrl = Uri.parse('https://www.google.com/maps/dir/?api=1&destination=$destLat,$destLng&travelmode=$modeParam');

    if (await canLaunchUrl(googleNavUri)) {
      await launchUrl(googleNavUri, mode: LaunchMode.externalApplication);
    } else {
      await launchUrl(universalUrl, mode: LaunchMode.externalApplication);
    }
  }

  Future<void> openDialer(String phoneNumber) async {
    final Uri telUri = Uri(scheme: 'tel', path: phoneNumber);

    if (await canLaunchUrl(telUri)) {
      await launchUrl(telUri, mode: LaunchMode.externalApplication);
    } else {
      throw 'Could not open dialer for $phoneNumber';
    }
  }

  FutureOr<void> getNearestER() async {
    isERListLoading = true;
    nearestERList = [];
    nearestERFilteredList = [];
    notifyListeners();
    var response = await emergencyServicesRepo.getNearestEr();
    isERListLoading = false;
    notifyListeners();

    response.fold(
      (failure) async {},
      (apiResponse) {
        isERListLoading = false;
        if (apiResponse.messageStatus == 1) {
          nearestERList = apiResponse.data!;
          nearestERFilteredList = nearestERList;
        }
      },
    );
  }

  GMSMapServices.CameraPosition getGMSLocation() {
    return GMSMapServices.CameraPosition(target: GMSMapServices.LatLng(appState.userLat, appState.userLong), zoom: 18);
  }

  handleGMSMapCameraMoved(GMSMapServices.CameraPosition value) {
    //todo_section handle the camera moved position for GMS devices
  }

  HMSCameraServices.CameraPosition getHMSLocation() {
    return HMSCameraServices.CameraPosition(target: HMSCameraServices.LatLng(appState.userLat, appState.userLong), zoom: 18);
  }

  handleHMSMapCameraMoved(HMSCameraServices.CameraPosition value) {
    //todo_section handle the camera moved position for HMS devices
  }

  void navigateTOAmbulancePage() {
    placeValueInController();
    flushData();
    selectedFacility = FacilitySelection.ALL;

    if (appState.isAuthenticated) {
      locationUtils!.getLocation(
          isShowConfirmDialog: true,
          onSuccess: (position) {
            getProjects();
            updateBottomSheetState(BottomSheetType.FIXED);
            navServices.push(
              CustomPageRoute(page: CallAmbulancePage(), direction: AxisDirection.down),
            );
          });
    } else {
      dialogService.showErrorBottomSheet(
          message: LocaleKeys.loginToUseService.tr(),
          onOkPressed: () {
            navServices.pop();
            navServices.pushAndReplace(AppRoutes.loginScreen);
          });
    }
  }

  void navigateToEROnlineCheckIn() {
    navServices.push(
      CustomPageRoute(page: ErOnlineCheckinHome()),
    );
  }

  void navigateToEROnlineCheckInPaymentPage() {
    navServices.push(
      CustomPageRoute(page: ErOnlineCheckinPaymentDetailsPage()),
    );
  }

  void updateBottomSheetState(BottomSheetType sheetType) {
    // if (sheetType == BottomSheetType.EXPANDED && selectedHospital == null) {
    //   dialogService.showErrorBottomSheet(message: LocaleKeys.selectHospital.tr());
    //   return;
    // }
    bottomSheetType = sheetType;
    // if (sheetType == BottomSheetType.FIXED) {
    //   clearAppointmentData();
    // }
    notifyListeners();
  }

  void showError(String message) {
    dialogService.showErrorBottomSheet(message: message);
  }

  void setIsGMSAvailable(bool value) {
    notifyListeners();
  }

  Future<void> checkPatientERAdvanceBalance({Function(dynamic)? onSuccess, Function(String)? onError}) async {
    if (!isAdvanceERBalanceNeedToBeLoaded) return;

    final result = await emergencyServicesRepo.checkPatientERAdvanceBalance();

    result.fold(
      // (failure) async => await errorHandlerService.handleError(failure: failure),
      (failure) {
        patientHasAdvanceERBalance = false;
        isERBookAppointment = true;
        isAdvanceERBalanceNeedToBeLoaded = false;
        if (onSuccess != null) {
          onSuccess(failure.message);
        }
      },
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
          // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
          patientHasAdvanceERBalance = false;
          isERBookAppointment = true;
          isAdvanceERBalanceNeedToBeLoaded = false;
        } else if (apiResponse.messageStatus == 1) {
          patientHasAdvanceERBalance = apiResponse.data;
          isERBookAppointment = !patientHasAdvanceERBalance;
          isAdvanceERBalanceNeedToBeLoaded = false;
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse);
          }
        }
      },
    );
  }

  Future<void> getPatientERPaymentInformation({Function(dynamic)? onSuccess, Function(String)? onError}) async {
    final result = await emergencyServicesRepo.checkPatientERPaymentInformation(projectID: selectedHospital!.iD);

    result.fold(
      (failure) {
        if (onError != null) {
          onError(failure.message);
        }
      },
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
        } else if (apiResponse.messageStatus == 1) {
          erOnlineCheckInPaymentDetailsResponse = apiResponse.data!;
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse);
          }
        }
      },
    );
  }

  Future<void> ER_CreateAdvancePayment(
      {required String paymentMethodName, required String paymentReference, Function(dynamic)? onSuccess, Function(String)? onError}) async {
    final result = await emergencyServicesRepo.createAdvancePaymentForER(
        projectID: selectedHospital!.iD,
        authUser: appState.getAuthenticatedUser()!,
        paymentAmount: erOnlineCheckInPaymentDetailsResponse.patientShareWithTax!,
        paymentMethodName: paymentMethodName,
        paymentReference: paymentReference);

    result.fold(
      (failure) {
        if (onError != null) {
          onError(failure.message);
        }
      },
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
        } else if (apiResponse.messageStatus == 1) {
          // erOnlineCheckInPaymentDetailsResponse = apiResponse.data!;
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse.data);
          }
        }
      },
    );
  }

  Future<void> addAdvanceNumberRequest(
      {required String advanceNumber,
      required String paymentReference,
      required String appointmentNo,
      Function(dynamic)? onSuccess,
      Function(String)? onError}) async {
    final result = await emergencyServicesRepo.addAdvanceNumberRequest(
        advanceNumber: advanceNumber, paymentReference: paymentReference, appointmentNo: appointmentNo);

    result.fold(
      (failure) async => await errorHandlerService.handleError(failure: failure),
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
          // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
        } else if (apiResponse.messageStatus == 1) {
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse);
          }
        }
      },
    );
  }

  Future<void> getProjectIDFromNFC({required String nfcCode, Function(dynamic)? onSuccess, Function(String)? onError}) async {
    final result = await emergencyServicesRepo.getProjectIDFromNFC(nfcCode: nfcCode);

    result.fold(
      // (failure) async => await errorHandlerService.handleError(failure: failure),
      (failure) {
        if (onError != null) {
          onError(failure.message);
        }
      },
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
          if (onError != null) {
            onError(apiResponse.errorMessage!);
          }
        } else if (apiResponse.messageStatus == 1) {
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse.data);
          }
        }
      },
    );
  }

  Future<void> autoGenerateInvoiceERClinic({required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
    final result = await emergencyServicesRepo.autoGenerateInvoiceERClinic(projectID: projectID);

    result.fold(
      // (failure) async => await errorHandlerService.handleError(failure: failure),
      (failure) {
        if (onError != null) {
          onError(failure.message);
        }
      },
      (apiResponse) {
        if (apiResponse.messageStatus == 2) {
          if (onError != null) {
            onError(apiResponse.data["InvoiceResponse"]["Message"]);
          }
        } else if (apiResponse.messageStatus == 1) {
          patientHasAdvanceERBalance = false;
          notifyListeners();
          if (onSuccess != null) {
            onSuccess(apiResponse.data);
          }
        }
      },
    );
  }

  Future<void> getTransportationOption() async {
    //handle the cache if the data is present then dont fetch it in the authenticated lifecycle
    if (appState.isAuthenticated == false) {
      dialogService.showErrorBottomSheet(
          message: LocaleKeys.loginToUseService.tr(),
          onOkPressed: () {
            navServices.pop();
            getIt<AuthenticationViewModel>().onLoginPressed();
          });
      return;
    }

    int? id = appState.getAuthenticatedUser()?.patientId;
    LoaderBottomSheet.showLoader(loadingText: LocaleKeys.gettingAmbulanceTransportOption.tr());

    notifyListeners();
    var response = await emergencyServicesRepo.getTransportationMethods(id: id);

    response.fold(
      (failure) async {
        LoaderBottomSheet.hideLoader();
      },
      (apiResponse) {
        transportationOptions = apiResponse.data!;
        LoaderBottomSheet.hideLoader();
        notifyListeners();
      },
    );
  }

  Future<void> getTransportationMethods() async {
    int? id = appState.getAuthenticatedUser()?.patientId;
    LoaderBottomSheet.showLoader(loadingText: LocaleKeys.gettingAmbulanceTransportOption.tr());

    notifyListeners();
    var response = await emergencyServicesRepo.getTransportationMethods(id: id);

    response.fold(
      (failure) async {
        LoaderBottomSheet.hideLoader();
      },
      (apiResponse) {
        transportationOptions = apiResponse.data!;
        LoaderBottomSheet.hideLoader();
        notifyListeners();
      },
    );
  }

  void setTransportationOption(PatientERTransportationMethod item) {
    selectedTransportOption = item;
    notifyListeners();
  }

  void updateCallingPlace(AmbulanceCallingPlace? value) {
    callingPlace = value!;
    notifyListeners();
  }

  void updateDirection(AmbulanceDirection? value) {
    ambulanceDirection = value!;
    notifyListeners();
  }

  void placeValueInController() {
    if (isGMSAvailable) {
      gmsController = Completer<GMSMapServices.GoogleMapController>();
    } else {
      hmsController = Completer<HMSCameraServices.HuaweiMapController>();
    }
  }

  void moveController(Location location) {
    if (isGMSAvailable) {
      gmsController?.future.then((controller) {
        controller.animateCamera(
          GMSMapServices.CameraUpdate.newCameraPosition(
            GMSMapServices.CameraPosition(
              target: GMSMapServices.LatLng(location.lat, location.lng),
              zoom: 18,
            ),
          ),
        );
      });
    } else {
      hmsController?.future.then((controller) {
        controller.animateCamera(
          HMSCameraServices.CameraUpdate.newCameraPosition(
            HMSCameraServices.CameraPosition(
              target: HMSCameraServices.LatLng(location.lat, location.lng),
              zoom: 18,
            ),
          ),
        );
      });
    }
  }

  void moveToCurrentLocation() {
    moveController(Location(lat: appState.userLat, lng: appState.userLong));
  }

  FutureOr<void> getProjects() async {
    // if (hospitalList.isNotEmpty) return;
    var response = await emergencyServicesRepo.getProjectList();

    response.fold(
      (failure) async {},
      (apiResponse) async {
        List<HospitalsModel>? data = apiResponse.data;
        if (data == null) return;
        hospitalList = data;
        hmgHospitalList = data.where((e) => e.isHMC == false).toList();
        hmcHospitalList = data.where((e) => e.isHMC == true).toList();
        hmgCount = hmgHospitalList?.length ?? 0;
        hmcCount = hmcHospitalList?.length ?? 0;
        getDisplayList();
        notifyListeners();
      },
    );
  }

  setSelectedFacility(FacilitySelection selection) {
    selectedFacility = selection;
    notifyListeners();
  }

  searchHospitals(String query) {
    if (query.isEmpty) {
      getDisplayList();
      return;
    }
    List<HospitalsModel>? sourceList;
    switch (selectedFacility) {
      case FacilitySelection.ALL:
        sourceList = hospitalList;
        break;
      case FacilitySelection.HMG:
        sourceList = hmgHospitalList;
        break;
      case FacilitySelection.HMC:
        sourceList = hmcHospitalList;
        break;
    }
    displayList = sourceList?.where((hospital) => hospital.name != null && hospital.name!.toLowerCase().contains(query.toLowerCase())).toList();
    notifyListeners();
  }

  getDisplayList() {
    switch (selectedFacility) {
      case FacilitySelection.ALL:
        displayList = hospitalList;
        break;
      case FacilitySelection.HMG:
        displayList = hmgHospitalList;
        break;
      case FacilitySelection.HMC:
        displayList = hmcHospitalList;
        break;
    }
    notifyListeners();
  }

  void setSelectedHospital(HospitalsModel? hospital) {
    selectedHospital = hospital;
    notifyListeners();
  }

  String? getSelectedHospitalName() {
    return selectedHospital?.getName(isArabic);
  }

  void updateThePickupPlaceFromLocation(bool value) {
    pickupFromInsideTheLocation = value;
    notifyListeners();
  }

  void flushData() {
    selectedHospital = null;
    displayList = hospitalList;
    selectedFacility = FacilitySelection.ALL;
    pickupFromInsideTheLocation = false;
    haveAnAppointment = false;
    appointment = null;
    notifyListeners();
  }

  void clearAppointmentData() {
    haveAnAppointment = false;
    appointment = null;
    notifyListeners();
  }

  void flushPickupInformation() {
    ambulanceDirection = AmbulanceDirection.ONE_WAY;
    callingPlace = AmbulanceCallingPlace.FROM_HOSPITAL;
    notifyListeners();
  }

  num getTotalPrice() {
    print("the ambulance direction is $ambulanceDirection");
    switch (ambulanceDirection) {
      case AmbulanceDirection.ONE_WAY:
        return selectedTransportOption?.priceTotal ?? 0;
      case AmbulanceDirection.TWO_WAY:
        return (selectedTransportOption?.priceTotal ?? 0) * 2;
    }
  }

  Future<void> updateAppointment(bool value) async {
    if (value) {
      await getAppointments();
    } else {
      clearAppointmentData();
    }
    if (appointments?.isNotEmpty == true) {
      haveAnAppointment = value;
    }
    notifyListeners();
  }

  Future<void> getAppointments() async {
    LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingAppointment.tr());
    var result = await appointmentRepo.getPatientAppointments(isActiveAppointment: true, isArrivedAppointments: false);
    LoaderBottomSheet.hideLoader();

    result.fold((failure) {
      haveAnAppointment = false;
      notifyListeners();
      errorHandlerService.handleError(failure: failure);
    }, (response) {
      appointments = response.data;
      if (appointments?.isEmpty == true) {
        haveAnAppointment = false;
        dialogService.showErrorBottomSheet(message: LocaleKeys.NoBookedAppointments.tr());
      }
      notifyListeners();
    });
  }

  void setSelectedAppointment(PatientAppointmentHistoryResponseModel selectedAppointment) {
    appointment = selectedAppointment;
    notifyListeners();
  }

  void checkHasAppointment() {
    if (appointment == null) {
      haveAnAppointment = false;
    }
    notifyListeners();
  }

  FutureOr<void> submitAmbulanceRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction) async {
    if (false == haveAnAppointment && null == selectedHospital) {
      dialogService.showErrorBottomSheet(message: LocaleKeys.selectHospital.tr());
      return;
    }
    PatientER_RC request = createRequest(result, place, placePrediction);
    navServices.push(CustomPageRoute(page: RequestingServicesPage()));

    var response = await emergencyServicesRepo.submitAmbulanceRequest(request);
    response.fold((failure) {
      navServices.pushAndRemoveUntil(
          CustomPageRoute(
              page: TrackingScreen(
            state: OrderTrackingState.failed,
          )),
          ModalRoute.withName("/EmergencyServicesPage"));
    }, (success) {
      getTransportationOrders(shouldNavigateToTrackingScreen: true);
    });
  }

  Future<void> getTransportationOrders({bool shouldNavigateToTrackingScreen = false, bool showLoader = false}) async {
    if (shouldNavigateToTrackingScreen == false && showLoader) {
      LoaderBottomSheet.showLoader(loadingText: "Fetching Orders");
    }
    int? id = appState.getAuthenticatedUser()?.patientId;
    historyLoading = true;
    notifyListeners();

    var response = await emergencyServicesRepo.getTransportationOrders(id: id);
    if (shouldNavigateToTrackingScreen == false && showLoader) {
      LoaderBottomSheet.hideLoader();
    }
    response.fold(
      (failure) async {
        historyLoading = false;
        notifyListeners();
        if (shouldNavigateToTrackingScreen) {
          navServices.pushAndRemoveUntil(
              CustomPageRoute(page: TrackingScreen(state: OrderTrackingState.waitingForCall)), ModalRoute.withName("/EmergencyServicesPage"));
        }
      },
      (apiResponse) {
        if (shouldNavigateToTrackingScreen) {
          navServices.pushAndRemoveUntil(
              CustomPageRoute(
                  page: TrackingScreen(
                state: OrderTrackingState.waitingForCall,
                order: apiResponse.data?.firstWhere((element) => element.statusId == 1),
              )),
              ModalRoute.withName("/EmergencyServicesPage"));
        }
        historyLoading = false;
        ambulanceOrders = apiResponse.data;
        allOrders.clear();
        allOrders.addAll(ambulanceOrders ?? []);
        allOrders.addAll(ordersRRT?.completedOrders ?? []);
        changeOrderDisplayItems(OrderDislpay.ALL);
        notifyListeners();
      },
    );
  }

  PatientER_RC createRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction) {
    PatientER_RC request = PatientER_RC();
    TransportationDetails transportationDetails = TransportationDetails();
    transportationDetails.requesterIsOutSA = false;
    transportationDetails.pickupSpot = pickupFromInsideTheLocation ? 1 : 0;

    transportationDetails.tripType = ambulanceDirection == AmbulanceDirection.ONE_WAY ? 0 : 1;
    transportationDetails.ambulate = (transportationOptions.indexOf(selectedTransportOption!) + 1);
    transportationDetails.transportationType = selectedTransportOption?.iD.toString() ?? "";
    request.patientERTransportationMethod = selectedTransportOption;
    transportationDetails.pickupUrgency = 1;
    switch (callingPlace) {
      case AmbulanceCallingPlace.TO_HOSPITAL:
        transportationDetails.dropoffLatitude = selectedHospital?.latitude;
        transportationDetails.dropoffLongitude = selectedHospital?.longitude;
        transportationDetails.dropoffLocationName = selectedHospital?.name;
        transportationDetails.pickupLatitude = ((result?.geometry.location.lat) ?? place?.lat)?.toStringAsFixed(6);
        transportationDetails.pickupLongitude = ((result?.geometry.location.lng) ?? place?.lng)?.toStringAsFixed(6);
        transportationDetails.pickupLocationName = result?.formattedAddress ?? placePrediction?.description;
        transportationDetails.direction = 1;
        break;
      case AmbulanceCallingPlace.FROM_HOSPITAL:
        transportationDetails.pickupLatitude = selectedHospital?.latitude;
        transportationDetails.pickupLongitude = selectedHospital?.longitude;
        transportationDetails.pickupLocationName = selectedHospital?.name;
        transportationDetails.dropoffLatitude = ((result?.geometry.location.lat) ?? place?.lat)?.toStringAsFixed(6);
        transportationDetails.dropoffLongitude = ((result?.geometry.location.lng) ?? place?.lng)?.toStringAsFixed(6);
        transportationDetails.dropoffLocationName = result?.formattedAddress ?? placePrediction?.description;
        transportationDetails.direction = 0;
        break;
    }
    AuthenticatedUser? user = appState.getAuthenticatedUser();
    if (user == null) throw Exception("Authentication Required to Continue");

    request.patientIdentificationID = user.patientIdentificationNo;
    request.projectID = user.projectId;
    request.patientID = user.patientId;
    transportationDetails.requesterIsOutSA = false;
    transportationDetails.requesterMobileNo = user.mobileNumber;
    transportationDetails.requesterFileNo = user.patientId;
    transportationDetails.pickupDateTime = DateUtil.convertDateToStringLocation(DateTime.now());
    if (haveAnAppointment) {
      transportationDetails.appointmentNo = appointment!.appointmentNo.toString();
      transportationDetails.appointmentClinicName = appointment!.clinicName;
      transportationDetails.appointmentDoctorName = appointment!.doctorNameObj;
      transportationDetails.appointmentBranch = appointment!.projectName;
      transportationDetails.appointmentTime = appointment!.appointmentDate;
      transportationDetails.haveAppointment = 1;
      transportationDetails.dropoffLatitude = appointment!.latitude;
      transportationDetails.dropoffLongitude = appointment!.longitude;
      transportationDetails.dropoffLocationName = appointment!.projectName;
    }

    transportationDetails.pickupSpot = pickupFromInsideTheLocation ? 1 : 0;
    transportationDetails.ambulate = 3;
    transportationDetails.ambulateTitle = "none";
    transportationDetails.notes = "";
    request.transportationDetails = transportationDetails;

    return request;
  }

  void clearSearchText() {
    searchController.clear();
  }

  Future<void> cancelOrder(AmbulanceRequestOrdersModel? order, {bool shouldPop = false}) async {
    dialogService.showCommonBottomSheetWithoutH(
        message: LocaleKeys.doYouWantToCancelTheRequest.tr(),
        onOkPressed: () async {
          navServices.pop();
          LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingRequest.tr());
          var response = await emergencyServicesRepo.cancelOrder(order?.iD, appState.getAuthenticatedUser()?.patientId ?? 0);
          LoaderBottomSheet.hideLoader();
          response.fold((failure) => errorHandlerService.handleError(failure: failure), (success) {
            getTransportationOrders();
            if (shouldPop) navServices.pop();
          });
        },
        onCancelPressed: () {
          navServices.pop();
        });
  }

  RRTRequestModel createRRTRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction) {
    AuthenticatedUser? user = appState.getAuthenticatedUser();
    if (user == null) throw Exception("Authentication Required to Continue");

    RRTRequestModel rrtRequestModel = new RRTRequestModel();
    Procedures procedures = new Procedures();
    rrtRequestModel.procedures = [];

    procedures.serviceID = selectedRRTProcedure?.procedureID;

    rrtRequestModel.latitude = ((result?.geometry.location.lat) ?? place?.lat);
    rrtRequestModel.longitude = ((result?.geometry.location.lat) ?? place?.lat);
    rrtRequestModel.additionalDetails = "";
    rrtRequestModel.nationality = user.nationalityId;
    rrtRequestModel.paymentAmount = selectedRRTProcedure?.patientShareWithTax;
    rrtRequestModel.nearestProjectId = 0;
    rrtRequestModel.patientId = user.patientId;
    rrtRequestModel.patientOutSa = user.outSa;
    rrtRequestModel.procedures!.add(procedures);

    return rrtRequestModel;
  }

  ///method to toggle the value for the aggremnent to the terms and conditon for the rrt
  void setTermsAndConditions(bool value) {
    agreedToTermsAndCondition = value;
    notifyListeners();
  }

  FutureOr<void> submitRRTRequest(GeocodeResult? result, PlaceDetails? place, PlacePrediction? placePrediction) async {
    RRTRequestModel request = createRRTRequest(result, place, placePrediction);
    navServices.push(CustomPageRoute(page: RequestingServicesPage()));

    var response = await emergencyServicesRepo.submitRRTRequest(request);
    response.fold((failure) {
      navServices.pushAndRemoveUntil(
          CustomPageRoute(
              page: TrackingScreen(
            isRRTOrder: true,
            state: OrderTrackingState.failed,
          )),
          ModalRoute.withName("/EmergencyServicesPage"));
    }, (success) {
      getRRTOrders(shouldNavigateToTrackingScreen: true);
    });
  }

  Future<void> getRRTOrders({bool shouldNavigateToTrackingScreen = false, bool showLoader = false}) async {
    if (shouldNavigateToTrackingScreen == false && showLoader) {
      LoaderBottomSheet.showLoader(loadingText: "Fetching Orders");
    }
    historyLoading = true;
    notifyListeners();
    int? id = appState.getAuthenticatedUser()?.patientId;

    var response = await emergencyServicesRepo.getRRTOrders(id: id);
    if (shouldNavigateToTrackingScreen == false && showLoader) {
      LoaderBottomSheet.hideLoader();
    }
    response.fold(
      (failure) async {
        historyLoading = false;
        notifyListeners();
        if (shouldNavigateToTrackingScreen) {
          navServices.pushAndRemoveUntil(CustomPageRoute(page: TrackingScreen(isRRTOrder: true, state: OrderTrackingState.waitingForCall)),
              ModalRoute.withName("/EmergencyServicesPage"));
        }
      },
      (apiResponse) {
        if (shouldNavigateToTrackingScreen) {
          navServices.pushAndRemoveUntil(
              CustomPageRoute(
                  page: TrackingScreen(
                state: OrderTrackingState.waitingForCall,
                isRRTOrder: true,
                rrtOrder: apiResponse.data?.pendingOrders.first,
              )),
              ModalRoute.withName("/EmergencyServicesPage"));
        }
        historyLoading = false;
        ordersRRT = apiResponse.data;
        allOrders.clear();
        allOrders.addAll(ambulanceOrders ?? []);
        allOrders.addAll(ordersRRT?.completedOrders ?? []);
        changeOrderDisplayItems(OrderDislpay.ALL);
        notifyListeners();
      },
    );
  }

  FutureOr<void> cancelRRTOrder(int? orderID, {bool shouldPop = false}) async {
    dialogService.showCommonBottomSheetWithoutH(
        message: LocaleKeys.doYouWantToCancelTheRequest.tr(),
        onOkPressed: () async {
          navServices.pop();
          LoaderBottomSheet.showLoader(loadingText: LocaleKeys.cancellingRequest.tr());
          var response = await emergencyServicesRepo.cancelRRTOrder(orderID);
          LoaderBottomSheet.hideLoader();
          response.fold((failure) => errorHandlerService.handleError(failure: failure), (success) {
            getRRTOrders();
            if (shouldPop) navServices.pop();
          });
        },
        onCancelPressed: () {
          navServices.pop();
        });
  }

  void changeOrderDisplayItems(OrderDislpay currentlyDisplayedOrder) {
    this.currentlyDisplayedOrder = currentlyDisplayedOrder;
    switch (currentlyDisplayedOrder) {
      case OrderDislpay.ALL:
        orderDisplayList = List.from(allOrders);
        break;
      case OrderDislpay.RRT:
        orderDisplayList = List.from(ordersRRT?.completedOrders ?? []);
        break;
      case OrderDislpay.AMBULANCE:
        orderDisplayList = List.from(ambulanceOrders ?? []);
        break;
    }

    orderDisplayList = _sortOrdersByDate(orderDisplayList);
    notifyListeners();
  }

  List _sortOrdersByDate(List list) {
    list.sort((a, b) {
      final int? dateA = _parseCreatedDate(a)?.millisecondsSinceEpoch;
      final int? dateB = _parseCreatedDate(b)?.millisecondsSinceEpoch;
      print("the dateA is $dateA and dateB is $dateB");
      if (dateA == null && dateB == null) return 0;
      if (dateA == null) return 1;
      if (dateB == null) return -1;
      return dateB.compareTo(dateA);
    });
    return list;
  }

  DateTime? _parseCreatedDate(dynamic order) {
    final String? raw = _getCreatedDate(order);


    return DateTime.tryParse(raw??"");
  }

  String? _getCreatedDate(dynamic order) {
    if (order is AmbulanceRequestOrdersModel) return order.created;
    if (order is GetCMCAllOrdersResponseModel) return order.created;
    return null;
  }

  void openRRT(BuildContext context) {
    if (appState.isAuthenticated) {
      if (agreedToTermsAndCondition == false) {
        dialogService.showErrorBottomSheet(
            message: LocaleKeys.pleaseAcceptTermsConditions.tr(),
            onOkPressed: () {
              if (navServices.context == null) return;
              showCommonBottomSheetWithoutHeight(
                navServices.context!,
                padding: EdgeInsets.only(top: 24.h),
                titleWidget: Transform.flip(
                  flipX: isArabic,
                  child: Utils.buildSvgWithAssets(
                    icon: AppAssets.arrow_back,
                    iconColor: Color(0xff2B353E),
                    fit: BoxFit.contain,
                  ),
                ).onPress(() {
                  navServices.pop();
                }),
                // title: "Rapid Response Team (RRT)".needTranslation,
                child: RrtRequestTypeSelect(),
                isFullScreen: false,
                isCloseButtonVisible: true,
                hasBottomPadding: false,
                backgroundColor: AppColors.bottomSheetBgColor,
                callBackFunc: () {
                  navServices.pop();
                },
              );
            });
        return;
      }
      placeValueInController();
      context.read<LocationViewModel>().placeValueInController();
      locationUtils!.getLocation(
          isShowConfirmDialog: true,
          onSuccess: (position) async {
            updateBottomSheetState(BottomSheetType.FIXED);
            bool result = await navServices.push(
              CustomPageRoute(
                  page: MapUtilityScreen(
                    confirmButtonString: LocaleKeys.submitRequest.tr(),
                    titleString: LocaleKeys.selectLocation.tr(),
                    subTitleString: LocaleKeys.pleaseSelectTheLocation.tr(),
                    isGmsAvailable: appState.isGMSAvailable,
                  ),
                  direction: AxisDirection.down),
            );
            if (result) {
              LocationViewModel locationViewModel = getIt.get<LocationViewModel>();
              GeocodeResponse? response = locationViewModel.geocodeResponse;
              PlaceDetails? placeDetails = locationViewModel.placeDetails;
              PlacePrediction? placePrediction = locationViewModel.selectedPrediction;
              submitRRTRequest(response?.results.first, placeDetails, placePrediction);
            }
          });
    } else {
      dialogService.showErrorBottomSheet(
          message: LocaleKeys.loginToUseService.tr(),
          onOkPressed: () {
            navServices.pop();
            getIt<AuthenticationViewModel>().onLoginPressed();
          });
    }
  }

  clearRRTData() {
    selectedRRTProcedure = null;
  }

  FutureOr<void> getTermsAndConditions() async {
    LoaderBottomSheet.showLoader(loadingText: LocaleKeys.fetchingTermsAndConditions.tr());
    var response = await emergencyServicesRepo.getTermsAndCondition();
    LoaderBottomSheet.hideLoader();
    response.fold((failure) => errorHandlerService.handleError(failure: failure), (success) {
      termsAndConditions = success.data;
      notifyListeners();
      navServices.push(
        CustomPageRoute(page: TermsAndCondition(termsAndCondition: success.data ?? ""), direction: AxisDirection.down),
      );
    });
  }
}
