import 'dart:async';
import 'dart:convert';
import 'dart:math' show cos;
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_polyline_algorithm/google_polyline_algorithm.dart';
import 'package:location/location.dart';
import 'package:ride/constant/box_name.dart';
import 'package:ride/constant/credential.dart';
import 'package:ride/constant/links.dart';
import 'package:ride/controller/firebase/firbase_messge.dart';
import 'package:ride/controller/functions/crud.dart';
import 'package:ride/controller/functions/secure_storage.dart';
import 'package:ride/controller/payment/payment_controller.dart';
import 'package:ride/views/Rate/rate_captain.dart';
import 'package:ride/views/widgets/elevated_btn.dart';
import '../../main.dart';
import '../../models/model/locations.dart';
import '../functions/launch.dart';

class MapPassengerController extends GetxController {
  bool isLoading = true;
  TextEditingController placeController = TextEditingController();
  TextEditingController sosPhonePassengerProfile = TextEditingController();
  final sosFormKey = GlobalKey<FormState>();
  List data = [];
  List<LatLng> bounds = [];
  List places = [];
  LatLngBounds? boundsdata;
  List<Marker> markers = [];
  List<Polyline> polyLines = [];
  late LatLng myLocation;
  late LatLng newMyLocation = const LatLng(32.115295, 36.064773);
  LatLng myDestination = const LatLng(32.115295, 36.064773);
  final List<LatLng> polylineCoordinates = [];
  List<LatLng> carsLocationByPassenger = [];
  List<LatLng> driverCarsLocationToPassengerAfterApplied = [];
  BitmapDescriptor markerIcon = BitmapDescriptor.defaultMarker;
  BitmapDescriptor carIcon = BitmapDescriptor.defaultMarker;
  double height = 150;
  DateTime currentTime = DateTime.now();
  final location = Location();
  late LocationData currentLocation;
  double heightMenu = 0;
  double widthMenu = 0;
  double heightPickerContainer = 90;
  double mainBottomMenuMap = Get.height * .2;
  bool heightMenuBool = false;
  bool isPickerShown = false;
  bool isBottomSheetShown = false;
  bool mapType = false;
  bool mapTrafficON = false;
  bool isCancelRidePageShown = false;
  bool isCashConfirmPageShown = false;
  bool isPaymentMethodPageShown = false;
  bool isRideFinished = false;
  bool rideConfirm = false;
  bool isMainBottomMenuMap = true;
  double heightBottomSheetShown = 0;
  double cashConfirmPageShown = 250;
  late String driverId;
  double widthMapTypeAndTraffic = 50;
  double paymentPageShown = Get.height * .6;
  late LatLng southwest;
  late LatLng northeast;
  List<CarLocationModel> carLocations = <CarLocationModel>[];
  var dataCarsLocationByPassenger;
  var datadriverCarsLocationToPassengerAfterApplied;
  CarLocation? nearestCar;
  late Timer markerReloadingTimer;
  bool shouldFetch = true; // Flag to determine if fetch should be executed
  int selectedPassengerCount = 1;
  double progress = 0;
  double progressTimerToPassengerFromDriverAfterApplied = 0;
  int durationTimer = 25;
  late int durationToRide;
  int remainingTime = 25;
  int remainingTimeToPassengerFromDriverAfterApplied = 60;
  int timeToPassengerFromDriverAfterApplied = 0;
  Timer? timerToPassengerFromDriverAfterApplied;
  bool rideTimerBegin = false;
  double progressTimerRideBegin = 0;
  int remainingTimeTimerRideBegin = 60;
  String stringRemainingTimeRideBegin = '';
  late String rideId;
  late String driverToken;
  int carsOrder = 0;

  void onChangedPassengerCount(int newValue) {
    selectedPassengerCount = newValue;
    update();
  }

// final mainBottomMenuMap = GlobalKey<AnimatedContainer>();
  void changeBottomSheetShown() {
    isBottomSheetShown = !isBottomSheetShown;
    heightBottomSheetShown = isBottomSheetShown == true ? 250 : 0;
    update();
  }

  void changeCashConfirmPageShown() {
    isCashConfirmPageShown = !isCashConfirmPageShown;
    cashConfirmPageShown = isCashConfirmPageShown == true ? 250 : 0;
    update();
  }

  void changePaymentMethodPageShown() {
    isPaymentMethodPageShown = !isPaymentMethodPageShown;
    paymentPageShown = isPaymentMethodPageShown == true ? Get.height * .6 : 0;
    update();
  }

  void changeMapType() {
    mapType = !mapType;
    // heightButtomSheetShown = isButtomSheetShown == true ? 240 : 0;
    update();
  }

  void changeMapTraffic() {
    mapTrafficON = !mapTrafficON;
    update();
  }

  void sendSMS(String to) async {
    // Get the driver's phone number.
    String driverPhone =
        dataCarsLocationByPassenger['message'][carsOrder]['phone'].toString();

    // Format the message.
    String message =
        'Hi! This is ${box.read(BoxName.name)}. I am using Sefer to ride with ${dataCarsLocationByPassenger['message'][carsOrder]['first_name'].toString()} as the driver. ${dataCarsLocationByPassenger['message'][carsOrder]['first_name'].toString()} is driving a ${dataCarsLocationByPassenger['message'][carsOrder]['model'].toString()} with license plate ${dataCarsLocationByPassenger['message'][carsOrder]['license_plate'].toString()}. I am currently located at $myLocation. If you need to reach me, please contact the driver directly at $driverPhone.';

    // Launch the URL to send the SMS.
    launchCommunication('sms', to, message);
  }

  void sendWhatsapp(String to) async {
    // Get the driver's phone number.
    String driverPhone =
        dataCarsLocationByPassenger['message'][carsOrder]['phone'].toString();

    // Format the message.
    String message =
        'Hi! This is ${box.read(BoxName.name)}. I am using Sefer to ride with ${dataCarsLocationByPassenger['message'][carsOrder]['first_name'].toString()} as the driver. ${dataCarsLocationByPassenger['message'][carsOrder]['first_name'].toString()} is driving a ${dataCarsLocationByPassenger['message'][carsOrder]['model'].toString()} with license plate ${dataCarsLocationByPassenger['message'][carsOrder]['license_plate'].toString()}. I am currently located at $myLocation. If you need to reach me, please contact the driver directly at $driverPhone.';

    // Launch the URL to send the SMS.
    launchCommunication('whatsapp', to, message);
  }

  void changeCancelRidePageShow() {
    // rideConfirm == true
    //     ?
    isCancelRidePageShown = !isCancelRidePageShown;
    // : cancelRide();
    update();
  }

  void getDrawerMenu() {
    heightMenuBool = !heightMenuBool;
    widthMapTypeAndTraffic = heightMenuBool == true ? 0 : 50;
    heightMenu = heightMenuBool == true ? 100 : 0;
    widthMenu = heightMenuBool == true ? 110 : 0;
    update();
  }

  String stringRemainingTimeToPassenger = '';

  void startTimerToPassengerFromDriverAfterApplied() async {
    for (int i = 0; i <= timeToPassengerFromDriverAfterApplied; i++) {
      await Future.delayed(const Duration(seconds: 1));
      progressTimerToPassengerFromDriverAfterApplied =
          i / timeToPassengerFromDriverAfterApplied;
      remainingTimeToPassengerFromDriverAfterApplied =
          timeToPassengerFromDriverAfterApplied - i;

      if (remainingTimeToPassengerFromDriverAfterApplied < 69) {
        if (rideTimerBegin == false) {
          getBeginRideFromDriver();
        }
      }

      int minutes =
          (remainingTimeToPassengerFromDriverAfterApplied / 60).floor();
      int seconds = remainingTimeToPassengerFromDriverAfterApplied % 60;
      stringRemainingTimeToPassenger =
          '$minutes:${seconds.toString().padLeft(2, '0')}';
      update();
    }
  }

  void rideIsBeginPassengerTimer() async {
    for (int i = 0; i <= durationToRide; i++) {
      await Future.delayed(const Duration(seconds: 1));
      progressTimerRideBegin = i / durationToRide;
      remainingTimeTimerRideBegin = durationToRide - i;

      int minutes = (remainingTimeTimerRideBegin / 60).floor();
      int seconds = remainingTimeTimerRideBegin % 60;
      stringRemainingTimeRideBegin =
          '$minutes:${seconds.toString().padLeft(2, '0')}';
      update();
    }

    rideTimerBegin = false;
    isRideFinished = true;
    update();
    print('rideTimerBegin: $rideTimerBegin');
    print('isRideFinished: $isRideFinished');
    Get.to(() => RateCaptainFromPassenger(), arguments: {
      'driverId': driverId.toString(),
      'rideId': rideId.toString(),
    });
  }

  void getBeginRideFromDriver() async {
    var res = await CRUD()
        .get(link: AppLink.getRideStatusBegin, payload: {'ride_id': rideId});
    var decode = jsonDecode(res);

    if (decode['data']['status'] == 'Begin') {
      timeToPassengerFromDriverAfterApplied = 0;
      remainingTime = 0;
      remainingTimeToPassengerFromDriverAfterApplied = 0;
      // isCancelRidePageShown = true;
      rideIsBeginPassengerTimer();
      // print('rideTimerBegin: $rideTimerBegin');
      rideTimerBegin = true;
      update();
    }
  }

  void driverArrivePassenger() {
    timeToPassengerFromDriverAfterApplied = 0;
    remainingTime = 0;
    // isCancelRidePageShown = true;
    update();
    rideIsBeginPassengerTimer();
  }

  void cancelTimerToPassengerFromDriverAfterApplied() {
    timerToPassengerFromDriverAfterApplied?.cancel();
  }

  void clearPlaces() {
    places = [];
    update();
  }

  int selectedReason = -1;
  String? cancelNote;
  void selectReason(int index, String note) {
    selectedReason = index;
    cancelNote = note;
    update();
  }

  changeConfirmRide() async {
    PaymentController paymentController = Get.find<PaymentController>();
    rideConfirm = true;
    shouldFetch = true;
    isBottomSheetShown = false;
    timeToPassengerFromDriverAfterApplied = 60;
    driverToken =
        dataCarsLocationByPassenger['message'][carsOrder]['token'].toString();
    update();
    // print('rideConfirm= $rideConfirm');

    await getCarsLocationByPassenger();
    await CRUD().post(link: AppLink.addRides, payload: {
      "start_location": //'${data[0]['start_address']}',
          '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
      "end_location": //'${data[0]['end_address']}',
          '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
      "date": DateTime.now().toString(),
      "time": DateTime.now().toString(),
      "endtime": durationToAdd.toString(),
      "price": totalPassenger.toString(),
      "passenger_id": box.read(BoxName.passengerID).toString(),
      "driver_id": dataCarsLocationByPassenger['message'][carsOrder]
              ['driver_id']
          .toString(),
      "status": "waiting",
      "price_for_driver": totalDriver.toString(),
      "price_for_passenger": totalME.toString(),
      "distance": distance.toString()
    }).then((value) {
      // print(jsonDecode(value)['message']);
      // List<String> body = [
      rideId = jsonDecode(value)['message'];
      List<String> body = [
        '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
        '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
        totalPassenger.toString(),
        totalDriver.toString(),
        duration.toString(),
        distance.toString(),
        dataCarsLocationByPassenger['message'][carsOrder]['id'].toString(),
        box.read(BoxName.passengerID).toString(),
        box.read(BoxName.name).toString(),
        box.read(BoxName.tokenFCM).toString(),
        box.read(BoxName.phone).toString(),
        durationByPassenger.toString(),
        distanceByPassenger.toString(),
        paymentController.isWalletChecked.toString(),
        dataCarsLocationByPassenger['message'][carsOrder]['token'].toString(),
        duration1.toString(),
        rideId,
        rideTimerBegin.toString(),
        dataCarsLocationByPassenger['message'][carsOrder]['driver_id']
            .toString(),
        durationToRide.toString()
      ];
      FirebaseMessagesController().sendNotificationToDriverMAP(
        'Order',
        jsonDecode(value)['message'].toString(),
        dataCarsLocationByPassenger['message'][carsOrder]['token'].toString(),
        body,
      );
      // print(dataCarsLocationByPassenger);
      // print(dataCarsLocationByPassenger['message'][0]['token'].toString());
    });
    delayAndFetchRideStatus(rideId);
    if (shouldFetch == false) {
      startTimer();
      update();
    }
    update();
  }

  void delayAndFetchRideStatus(String rideId) {
    Timer(const Duration(seconds: 1), () async {
      if (shouldFetch) {
        // print('shouldFetch is =$shouldFetch');
        var res = await CRUD()
            .get(link: AppLink.getRideStatus, payload: {'order_id': rideId});
        var decod = jsonDecode(res);
        print(' 0000000000000000000000000000000000000000000000000');
        print(decod['data']);
        if (decod['data'].toString() == 'Apply') {
          shouldFetch = false; // Stop further fetches
          rideConfirm = false;
          update();
          startTimer();
        } else if (decod['data'].toString() == 'Refused') {
          carsOrder++;
          update();
          changeConfirmRide();
        } else {
          delayAndFetchRideStatus(
              rideId); // Repeat the delay and fetch operation
          update();
        }
      }
    });
  }

  void startTimer() async {
    for (int i = 0; i <= durationTimer; i++) {
      await Future.delayed(const Duration(seconds: 1));
      progress = i / durationTimer;
      remainingTime = durationTimer - i;
      if (remainingTime == 0) {
        rideConfirm = false;

        // print(timeToPassengerFromDriverAfterApplied);
        timeToPassengerFromDriverAfterApplied += duration1;
        // print(duration1);

        // print('timeToPassengerFromDriverAfterApplied====' +
        //     timeToPassengerFromDriverAfterApplied.toString());
        startTimerToPassengerFromDriverAfterApplied();
        update();
      }
      update();
    }
    timerEnded();
  }

  void timerEnded() async {
    print('Timer ended');

    runEvery30SecondsUntilConditionMet();
    isCancelRidePageShown = false;
    update();
  }

  Future<String> getRideStatus(int rideId) async {
    final response = await CRUD()
        .get(link: AppLink.getRideStatus, payload: {'order_id': rideId});

    return response['status'];
  }

  Future getCarsLocationByPassenger() async {
    // if (rideConfirm == false) {
    carsLocationByPassenger = [];
    LatLngBounds bounds =
        calculateBounds(myLocation.latitude, myLocation.longitude, 8000);
    print(
        'Southwest: ${bounds.southwest.latitude}, ${bounds.southwest.longitude}');
    print(
        'Northeast: ${bounds.northeast.latitude}, ${bounds.northeast.longitude}');

    var res =
        await CRUD().get(link: AppLink.getCarsLocationByPassenger, payload: {
      'southwestLat': southwest.latitude.toString(),
      'southwestLon': southwest.longitude.toString(),
      'northeastLat': northeast.latitude.toString(),
      'northeastLon': northeast.longitude.toString(),
    });
    if (res == 'failure') {
      Get.defaultDialog(
          title: 'No Car in your site.Sorry!',
          middleText: '',
          confirm: MyElevatedButton(
              title: 'Back',
              onPressed: () {
                Get.back();
                markerReloadingTimer.cancel();
              }));
    } else {
      dataCarsLocationByPassenger = jsonDecode(res);
      // print(dataCarsLocationByPassenger);
      driverId = dataCarsLocationByPassenger['message'][carsOrder]['driver_id']
          .toString();
      // print('driverId==============$driverId');
      for (var i = 0; i < dataCarsLocationByPassenger['message'].length; i++) {
        carsLocationByPassenger.add(LatLng(
            double.parse(dataCarsLocationByPassenger['message'][i]['latitude']),
            double.parse(
                dataCarsLocationByPassenger['message'][i]['longitude'])));
      }

      update();
      // }
    }
  }

  Future getDriverCarsLocationToPassengerAfterApplied() async {
    driverCarsLocationToPassengerAfterApplied = [];

    var res = await CRUD().get(
        link: AppLink.getDriverCarsLocationToPassengerAfterApplied,
        payload: {
          'driver_id': dataCarsLocationByPassenger['message'][carsOrder]
              ['driver_id']
        });

    datadriverCarsLocationToPassengerAfterApplied = jsonDecode(res);

    driverCarsLocationToPassengerAfterApplied.add(LatLng(
        double.parse(datadriverCarsLocationToPassengerAfterApplied['message']
            [carsOrder]['latitude']),
        double.parse(datadriverCarsLocationToPassengerAfterApplied['message']
            [carsOrder]['longitude'])));

    update();
  }

  Future runEvery30SecondsUntilConditionMet() async {
    // Calculate the duration of the trip in minutes.
    double tripDurationInMinutes = duration1 / 30;
    int loopCount = tripDurationInMinutes.ceil();
    // If the trip duration is less than or equal to 50 minutes, then break the loop.
    for (var i = 0; i < loopCount; i++) {
      // Wait for 50 seconds.
      await Future.delayed(const Duration(
          seconds:
              31)); // Run the `getDriverCarsLocationToPassengerAfterApplied()` function.
      await getDriverCarsLocationToPassengerAfterApplied();
      reloadMarkerDriverCarsLocationToPassengerAfterApplied();
    }
  }

  void reloadMarkerDriverCarsLocationToPassengerAfterApplied() {
    // Clear existing markers
    markers.clear();
    update();
    for (var i = 0; i < driverCarsLocationToPassengerAfterApplied.length; i++) {
// }
//     for (var item in driverCarsLocationToPassengerAfterApplied) {
      final marker = Marker(
        infoWindow: InfoWindow(
            title:
                '${driverCarsLocationToPassengerAfterApplied[i].latitude} minutes'),
        markerId: MarkerId(
            datadriverCarsLocationToPassengerAfterApplied['message'][0]['id']
                .toString()),
        position: LatLng(driverCarsLocationToPassengerAfterApplied[i].latitude,
            driverCarsLocationToPassengerAfterApplied[i].longitude),
      );
      markers.add(marker);
      update();
      mapController?.animateCamera(CameraUpdate.newLatLng(LatLng(
          driverCarsLocationToPassengerAfterApplied[i].latitude,
          driverCarsLocationToPassengerAfterApplied[i].longitude)));
      update();
    } // Update the map with the new markers
  }

  restCounter() {
    clearPlaces();
    clearPolyline();
    data = [];
    rideConfirm = false;
    shouldFetch = false;
    timeToPassengerFromDriverAfterApplied = 0;
    update();
  }

  Future cancelRide() async {
    print(rideConfirm);

    if (rideConfirm == false) {
      clearPlaces();
      clearPolyline();
      data = [];
      changeCancelRidePageShow();
      rideConfirm = false;
      shouldFetch = false;
      timeToPassengerFromDriverAfterApplied = 0;
      update();
    } else {
      clearPlaces();
      clearPolyline();
      data = [];
      rideConfirm = false;
      shouldFetch = false;
      timeToPassengerFromDriverAfterApplied = 0;
      changeCancelRidePageShow();
      remainingTime = 25;
      update();

      await CRUD().post(link: AppLink.addCancelRideFromPassenger, payload: {
        "driverID": FirebaseMessagesController()
            .driverID
            .toString(), // Convert to String
        "passengerID":
            box.read(BoxName.passengerID).toString(), // Convert to String
        "rideID": rideId.toString(), // Convert to String
        "note": cancelNote
      });

      update();
    }
  }

  void changePickerShown() {
    isPickerShown = !isPickerShown;
    heightPickerContainer = isPickerShown == true ? 150 : 90;
    update();
  }

  void changeMainBottomMenuMap() {
    isMainBottomMenuMap = !isMainBottomMenuMap;
    mainBottomMenuMap =
        isMainBottomMenuMap == true ? Get.height * .2 : Get.height * .66;
    if (heightMenuBool == true) {
      getDrawerMenu();
    }
    update();
  }

  changeHeight() {
    if (places.isEmpty) {
      height = 0;
      update();
    }
    height = 150;
    update();
  }

  hidePlaces() {
    height = 0;

    update();
  }

  Future getPlaces() async {
    var url =
        // '${AppLink.googleMapsLink}place/nearbysearch/json?location=${mylocation.longitude}&radius=25000&language=ar&keyword=&key=${placeController.text}${AppCredintials.mapAPIKEY}';
        '${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${placeController.text}&location=${myLocation.latitude},${myLocation.longitude}&radius=50000&language=ar&key=${AppCredintials.mapAPIKEY}';

    var response = await CRUD().getGoogleApi(link: url, payload: {});

    places = response['results'];
    print(places);
    update();
  }

  LatLng fromString(String location) {
    List<String> parts = location.split(',');
    double lat = double.parse(parts[0]);
    double lng = double.parse(parts[1]);
    return LatLng(lat, lng);
  }

  void clearPolyline() {
    polyLines = [];
    polylineCoordinates.clear();
    update();
  }

  void addCustomPicker() {
    ImageConfiguration config = const ImageConfiguration(
      size: Size(20, 20),
      // scale: 1.0,
    );
    BitmapDescriptor.fromAssetImage(config, 'assets/images/picker.png')
        .then((value) {
      markerIcon = value;
      update();
    });
  }

  void addCustomCarIcon() {
    ImageConfiguration config = ImageConfiguration(
      size: Size(Get.width * .6, Get.height * .6),
      // scale: 1.0,
    );
    BitmapDescriptor.fromAssetImage(config, 'assets/images/car.png')
        .then((value) {
      carIcon = value;
      update();
    });
  }

  Future<void> getLocation() async {
    isLoading = true;
    update();
    bool serviceEnabled;
    PermissionStatus permissionGranted;

    // Check if location services are enabled
    serviceEnabled = await location.serviceEnabled();
    if (!serviceEnabled) {
      serviceEnabled = await location.requestService();
      if (!serviceEnabled) {
        // Location services are still not enabled, handle the error
        return;
      }
    }

    // Check if the app has permission to access location
    permissionGranted = await location.hasPermission();
    if (permissionGranted == PermissionStatus.denied) {
      permissionGranted = await location.requestPermission();
      if (permissionGranted != PermissionStatus.granted) {
        // Location permission is still not granted, handle the error
        return;
      }
    }

    // Configure location accuracy
    LocationAccuracy desiredAccuracy = LocationAccuracy.high;

    // Get the current location
    LocationData _locationData = await location.getLocation();
    myLocation =
        (_locationData.latitude != null && _locationData.longitude != null
            ? LatLng(_locationData.latitude!, _locationData.longitude!)
            : null)!;

    // Print location details
    print('Accuracy: ${_locationData.accuracy}');
    print('Latitude: ${_locationData.latitude}');
    print('Longitude: ${_locationData.longitude}');
    print('Time: ${_locationData.time}');
    isLoading = false;
    update();
  }

  LatLngBounds calculateBounds(
      double centerLat, double centerLng, double radius) {
    // double radius = 4000; // 10 km in meters

    southwest = LatLng(
      centerLat - (radius / 111000),
      centerLng - (radius / (111000 * cos(centerLat))),
    );

    northeast = LatLng(
      centerLat + (radius / 111000),
      centerLng + (radius / (111000 * cos(centerLat))),
    );

    return LatLngBounds(southwest: southwest, northeast: northeast);
  }

  GoogleMapController? mapController;
  void onMapCreated(GoogleMapController controller) {
    mapController = controller;
    controller.getVisibleRegion();
    controller.animateCamera(
      CameraUpdate.newLatLng(myLocation),
    );
    update();
  }

  // void startMarkerReloading() {
  //   int count = 0;
  //   markerReloadingTimer = Timer.periodic(const Duration(seconds: 30), (timer) {
  //     print('timer==============================');
  //     reloadMarkers();
  //
  //     count++;
  //     if (count == 10) {
  //       timer.cancel();
  //     }
  //   });
  // }

  late Timer markerReloadingTimer2;
  late Timer markerReloadingTimer1;
  late int duration1;
  void startMarkerReloading() {
    // Schedule timer 1 to reload markers at a specific time
    DateTime scheduledTime1 = DateTime.now().add(const Duration(seconds: 20));
    markerReloadingTimer1 =
        Timer(scheduledTime1.difference(DateTime.now()), () {
      print('timer 1 ==============================');
      reloadMarkers();
    });

    // Schedule timer 2 to reload markers at a specific time
    DateTime scheduledTime2 = DateTime.now().add(const Duration(seconds: 40));
    markerReloadingTimer2 =
        Timer(scheduledTime2.difference(DateTime.now()), () {
      print('timer 2 ==============================');
      reloadMarkers();
    });
  }

  void reloadMarkers() async {
    await getCarsLocationByPassenger();

    // Clear existing markers
    // mapController!.showMarkerInfoWindow(MarkerId('g'));
    markers.clear();
    update();
    // if (rideConfirm) {
    getNearestDriverByPassengerLocation();
    // }
    // Add new markers
    // Example: Add a marker for each item in a list
    for (var item in carsLocationByPassenger) {
      final marker = Marker(
        infoWindow: InfoWindow(title: '${item.latitude} minutes'),
        markerId: MarkerId(duration1.toString()),
        position: LatLng(item.latitude, item.longitude),
        // Other properties for the marker, such as icon, info window, etc.
      );
      markers.add(marker);
    }

    // Update the map with the new markers
    mapController?.animateCamera(CameraUpdate.newLatLng(
        LatLng(myLocation.latitude, myLocation.longitude)));
  }

  String durationByPassenger = '';
  late DateTime newTime1 = DateTime.now();
  late DateTime timeFromDriverToPassenger = DateTime.now();
  String distanceByPassenger = '';
  late Duration durationFromDriverToPassenger;

  void getNearestDriverByPassengerLocation() async {
    if (polyLines.isEmpty || data.isEmpty) {
      if (rideConfirm == false) {
        double nearestDistance = double.infinity;
        for (var i = 0;
            i < dataCarsLocationByPassenger['message'].length;
            i++) {
          var carLocation = dataCarsLocationByPassenger['message'][i];

          // double distance1 = Geolocator.distanceBetween(
          //   mylocation.latitude,
          //   mylocation.longitude,
          //   double.parse(carLocation['latitude']),
          //   double.parse(carLocation['longitude']),
          // );
          // if (distance1 < nearestDistance) {
          //   nearestDistance = distance1;
          //   // nearestCarLocation = carLocation;
          //   nearestCar = CarLocation(
          //     distance: distance1,
          //     id: carLocation['driver_id'],
          //     latitude: double.parse(carLocation['latitude']),
          //     longitude: double.parse(carLocation['longitude']),
          //   );
          // }
          // isloading = true;
          update();
          // Make API request to get exact distance and duration
          String apiUrl =
              '${AppLink.googleMapsLink}distancematrix/json?destinations=${carLocation['latitude']},${carLocation['longitude']}&origins=${myLocation.latitude},${myLocation.longitude}&units=metric&key=${AppCredintials.mapAPIKEY}';
          var response = await CRUD().getGoogleApi(link: apiUrl, payload: {});
          if (response['status'] == "OK") {
            var data = response;
            // Extract distance and duration from the response and handle accordingly
            int distance1 = data['rows'][0]['elements'][0]['distance']['value'];
            distanceByPassenger =
                data['rows'][0]['elements'][0]['distance']['text'];
            duration1 = data['rows'][0]['elements'][0]['duration']['value'];

            durationFromDriverToPassenger =
                Duration(seconds: duration1.toInt());
            newTime1 = currentTime.add(durationFromDriverToPassenger);
            timeFromDriverToPassenger =
                newTime1.add(Duration(minutes: 2.toInt()));
            durationByPassenger =
                data['rows'][0]['elements'][0]['duration']['text'];
            update();
            if (distance1 < nearestDistance) {
              nearestDistance = distance1.toDouble();

              nearestCar = CarLocation(
                distance: distance1.toDouble(),
                duration: duration1.toDouble(),
                id: carLocation['driver_id'],
                latitude: double.parse(carLocation['latitude']),
                longitude: double.parse(carLocation['longitude']),
              );
              // isloading = false;
              update();
            }
          }

          // Handle the distance and duration as needed
          else {
            print(
                'Failed to retrieve distance and duration: ${response['status']}');
            // Handle the failure case
          }
        }
      }
    }
    print(nearestCar!.distance);
    print(nearestCar!.duration);
    print(nearestCar!.latitude);
    print(nearestCar!.longitude);
    print(nearestCar!.id);
  }

  late LatLngBounds boundsData;
  getMap(String origin, destination) async {
    var origin1 = fromString(origin);
    var destination1 = fromString(destination);
    isLoading = false;
    myDestination = destination1;
    myLocation = origin1;
    update();
    await getCarsLocationByPassenger();
    // print(carsLocationByPassenger);

    var url =
        ('${AppLink.googleMapsLink}directions/json?&language=en&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AppCredintials.mapAPIKEY}');

    var response = await CRUD().getGoogleApi(link: url, payload: {});
    data = response['routes'][0]['legs'];
    print(data);
    durationToRide = data[0]['duration']['value'];
    final points =
        decodePolyline(response["routes"][0]["overview_polyline"]["points"]);
    for (int i = 0; i < points.length; i++) {
      double lat = points[i][0].toDouble();
      double lng = points[i][1].toDouble();
      polylineCoordinates.add(LatLng(lat, lng));
    }
//  Define the northeast and southwest coordinates
    final bounds = response["routes"][0]["bounds"];

    LatLng northeast =
        LatLng(bounds['northeast']['lat'], bounds['northeast']['lng']);
    LatLng southwest =
        LatLng(bounds['southwest']['lat'], bounds['southwest']['lng']);

    // Create the LatLngBounds object
    boundsData = LatLngBounds(northeast: northeast, southwest: southwest);

// Calculate the zoom level based on the distance and screen size

    double distanceOfDestnation =
        getDistanceFromText(data[0]['distance']['text']);

    // Animate the camera to the adjusted bounds
    if (distanceOfDestnation <= 5) {
      mapController!.animateCamera(CameraUpdate.newLatLngZoom(myLocation, 14));
    } else if (distanceOfDestnation > 5 && distanceOfDestnation <= 8) {
      mapController!.animateCamera(CameraUpdate.newLatLngZoom(myLocation, 13));
    } else if (distanceOfDestnation > 8 && distanceOfDestnation < 16) {
      mapController!.animateCamera(CameraUpdate.newLatLngZoom(myLocation, 12));
    } else if (distanceOfDestnation >= 16 && distanceOfDestnation < 30) {
      mapController!.animateCamera(CameraUpdate.newLatLngZoom(myLocation, 11));
    } else if (distanceOfDestnation >= 30 && distanceOfDestnation < 100) {
      mapController!.animateCamera(CameraUpdate.newLatLngZoom(myLocation, 10));
    } else if (distanceOfDestnation >= 100) {
      mapController!.animateCamera(CameraUpdate.newLatLngZoom(myLocation, 7));
    }
    if (polyLines.isNotEmpty) {
      clearPolyline();
    } else {
      var polyline = Polyline(
        polylineId: PolylineId(response["routes"][0]["summary"]),
        points: polylineCoordinates,
        width: 10,
        color: Colors.blue,
      );

      polyLines.add(polyline);
      rideConfirm = false;
      update();
    }
  }

  showBottomSheet1() async {
    bottomSheet();
    isBottomSheetShown = true;
    heightBottomSheetShown = 250;

    update();
  }

  final promo = TextEditingController();
  bool promoTaken = false;
  void applyPromoCodeToPassenger() async {
    //TAWJIHI

    CRUD().get(link: AppLink.getPassengersPromo, payload: {
      'promo_code': promo.text,
    }).then((value) {
      if (value == 'failure') {
        Get.defaultDialog(
            title: 'Promo End !'.tr,
            confirm: MyElevatedButton(
              title: 'Back',
              onPressed: () {
                Get.back();
                Get.back();
              },
            ));
      }
      var decode = jsonDecode(value);

      if (decode["status"] == "success") {
        print(totalPassenger);
        var firstElement = decode["message"][0];
        totalPassenger = totalPassenger -
            (totalPassenger * int.parse(firstElement['amount']) / 100);
        promoTaken = true;
        update();
        print(totalPassenger);
        Get.back();
      }
    });
  }

  double getDistanceFromText(String distanceText) {
    // Remove any non-digit characters from the distance text
    String distanceValue = distanceText.replaceAll(RegExp(r'[^0-9.]+'), '');

    // Parse the extracted numerical value as a double
    double distance = double.parse(distanceValue);

    return distance;
  }

  late double totalME = 0;
  late double tax = 0;
  late double totalPassenger = 0;
  late double totalDriver = 0;
  late double averageDuration = 0;
  late double costDuration = 0;
  late double cost = 0;
  late double distance = 0;
  late double duration = 0;

  late Duration durationToAdd;
  late DateTime newTime = DateTime.now();
  Future bottomSheet() async {
    if (data.isNotEmpty) {
      String distanceText = await data[0]['distance']['text'];
      String durationText = await data[0]['duration']['text'];
      print(data[0]['duration']['text']);
      print('=================================');
      distance = getDistanceFromText(distanceText);
      duration = getDistanceFromText(durationText);
      durationToAdd = Duration(minutes: duration.toInt());
      DateTime currentTime = DateTime.now();
      newTime = currentTime.add(durationToAdd);
      averageDuration = duration / distance;
      costDuration = duration * averageDuration * 0.016;
      totalDriver = cost + costDuration;
      totalPassenger = totalDriver + (totalDriver * .16);
      tax = totalPassenger * .04;
      totalME = totalPassenger - totalDriver - tax;
      update();
      if (currentTime.hour >= 21) {
        if (distanceText.contains('km')) {
          cost = distance * 0.23;
          update();
        } else {
          cost = distance * 0.23 / 1000;
          update();
        }
      } else if (currentTime.hour < 5) {
        if (distanceText.contains('km')) {
          cost = distance * 0.25;
          update();
        } else {
          cost = distance * 0.25 / 1000;
          update();
        }
      } else if (currentTime.hour >= 13 && currentTime.hour <= 16) {
        if (averageDuration > 2.5) {
          if (distanceText.contains('km')) {
            cost = distance * 0.23;
            update();
          } else {
            cost = distance * 0.25 / 1000;
            update();
          }
        } else {
          if (distanceText.contains('km')) {
            cost = distance * 0.21;
            update();
          } else {
            cost = distance * 0.21 / 1000;
            update();
          }
        }
      } else {
        if (distanceText.contains('km')) {
          cost = distance * 0.21;
          update();
        } else {
          cost = distance * 0.21 / 1000;
          update();
        }
      }

      if (totalPassenger < 1) {
        totalPassenger = 1;
        update();
        if (totalDriver < .5) {
          totalDriver = .85;
          totalME = .11;
          update();
        } else {
          totalDriver = .95;
          totalME = .05;
          update();
        }
      }

      // buttomSheetMapPage();
      changeBottomSheetShown();
    }

    // Get.bottomSheet(
    //   Container(
    //     height: 130,
    //     decoration: const BoxDecoration(
    //         color: AppColor.secondaryColor,
    //         borderRadius: BorderRadius.only(
    //             topLeft: Radius.circular(15), topRight: Radius.circular(15))),
    //     child: data.isEmpty
    //         ? Center(
    //             child: Text(
    //             'Where are you want to go..',
    //             style: AppStyle.title,
    //           ))
    //         : Center(
    //             child: Column(
    //               children: [
    //                 Row(
    //                   mainAxisAlignment: MainAxisAlignment.spaceAround,
    //                   children: [
    //                     Text(
    //                       'distance is ${data[0]['distance']['text']}',
    //                       style: AppStyle.title,
    //                     ),
    //                     Text(
    //                       'duration is ${data[0]['duration']['text']}',
    //                       style: AppStyle.title,
    //                     ),
    //                   ],
    //                 ),
    //                 Row(
    //                   mainAxisAlignment: MainAxisAlignment.spaceAround,
    //                   children: [
    //                     Text(
    //                       'Cost for .21/km ${cost.toStringAsFixed(2)} ',
    //                       style: AppStyle.title,
    //                     ),
    //                     Text(
    //                       'costDuration ${averageDuration.toStringAsFixed(2)} is ${costDuration.toStringAsFixed(2)} ',
    //                       style: AppStyle.title,
    //                     ),
    //                   ],
    //                 ),
    //                 Row(
    //                   mainAxisAlignment: MainAxisAlignment.spaceAround,
    //                   children: [
    //                     Text(
    //                       'Cost for passenger ${totalPassenger.toStringAsFixed(2)} ',
    //                       style: AppStyle.title,
    //                     ),
    //                     Text(
    //                       'totaME  ${totaME.toStringAsFixed(2)} ',
    //                       style: AppStyle.title,
    //                     ),
    //                   ],
    //                 ),
    //                 Text(
    //                   'totalDriver  ${totalDriver.toStringAsFixed(2)}',
    //                   style: AppStyle.title,
    //                 ),
    //               ],
    //             ),
    //           ),
    //   ),
    //   elevation: 6,
    //   enableDrag: true,
    //   isScrollControlled: true,
    //   isDismissible: true,
    //   useRootNavigator: true,
    //   backgroundColor: Colors.transparent,
    //   barrierColor: AppColor.accentColor.withOpacity(.4),
    //   persistent: true,
    //   shape: ShapeBorder.lerp(
    //       RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
    //       RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
    //       0.5),
    // );
  }

  List<LatLng> polylineCoordinate = [];
  String? cardNumber;
  @override
  void onInit() async {
    await getLocation();
    await getCarsLocationByPassenger();
    getNearestDriverByPassengerLocation();
    addCustomPicker();
    addCustomCarIcon();
    startMarkerReloading();
    cardNumber = await SecureStorage().readData(BoxName.cardNumber);
    super.onInit();
  }
}

class CarLocation {
  final String id;
  final double latitude;
  final double longitude;
  final double distance;
  final double duration;

  CarLocation({
    required this.id,
    required this.latitude,
    required this.longitude,
    this.distance = 10000,
    this.duration = 10000,
  });
}
