import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:math' as math;
import 'package:sefer_driver/controller/home/captin/behavior_controller.dart';
import 'package:sefer_driver/controller/home/captin/home_captain_controller.dart';
import 'package:sefer_driver/views/widgets/mydialoug.dart';
import 'package:bubble_head/bubble.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.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:url_launcher/url_launcher.dart';

import '../../../constant/api_key.dart';
import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../constant/links.dart';
import '../../../constant/table_names.dart';
import '../../../main.dart';
import '../../../print.dart';
import '../../../views/Rate/rate_passenger.dart';
import '../../../views/home/Captin/home_captain/home_captin.dart';
import '../../firebase/firbase_messge.dart';
import '../../functions/crud.dart';
import '../../functions/encrypt_decrypt.dart';
import '../../functions/location_controller.dart';
import '../../functions/tts.dart';

class MapDriverController extends GetxController {
  bool isLoading = true;
  final formKey1 = GlobalKey<FormState>();
  final formKey2 = GlobalKey<FormState>();
  final formKeyCancel = GlobalKey<FormState>();
  final messageToPassenger = TextEditingController();
  final sosEmergincyNumberCotroller = TextEditingController();
  final cancelTripCotroller = TextEditingController();
  List data = [];
  List dataDestination = [];
  LatLngBounds? boundsData;
  BitmapDescriptor carIcon = BitmapDescriptor.defaultMarker;
  BitmapDescriptor passengerIcon = BitmapDescriptor.defaultMarker;
  BitmapDescriptor startIcon = BitmapDescriptor.defaultMarker;
  BitmapDescriptor endIcon = BitmapDescriptor.defaultMarker;
  final List<LatLng> polylineCoordinates = [];
  final List<LatLng> polylineCoordinatesDestination = [];
  List<Polyline> polyLines = [];
  List<Polyline> polyLinesDestination = [];
  Set<Marker> markers = {};
  late String passengerLocation;
  late String passengerDestination;
  late String step0;
  late String step1;
  late String step2;
  late String step3;
  late String step4;
  late String passengerWalletBurc;
  late String timeOfOrder;
  late String duration;
  late String totalCost;
  late String distance;
  late String passengerName;
  late String passengerEmail;
  late String totalPricePassenger;
  late String passengerPhone;
  late String rideId;
  late String isHaveSteps;
  late String paymentAmount;
  late String paymentMethod;
  late String passengerId;
  late String driverId;
  late String tokenPassenger;
  late String durationToPassenger;
  late String walletChecked;
  late String direction;
  late String durationOfRideValue;
  late String status;
  int timeWaitingPassenger = 5; //5 miniute
  bool isPassengerInfoWindow = false;
  bool isBtnRideBegin = false;
  bool isArrivedSend = true;
  bool isdriverWaitTimeEnd = false;
  bool isRideFinished = false;
  bool isRideStarted = false;
  bool isPriceWindow = false;
  double passengerInfoWindowHeight = Get.height * .38;
  double driverEndPage = 100;
  double progress = 0;
  double progressToPassenger = 0;
  double progressInPassengerLocationFromDriver = 0;
  bool isRideBegin = false;
  int progressTimerToShowPassengerInfoWindowFromDriver = 25;
  int remainingTimeToShowPassengerInfoWindowFromDriver = 25;
  int remainingTimeToPassenger = 60;
  int remainingTimeInPassengerLocatioWait = 60;
  bool isDriverNearPassengerStart = false;
  GoogleMapController? mapController;
  late LatLng myLocation;
  int remainingTimeTimerRideBegin = 60;
  String stringRemainingTimeRideBegin = '';
  String stringRemainingTimeRideBegin1 = '';
  double progressTimerRideBegin = 0;
  late Timer timer;
  String? mapAPIKEY;
  final zones = <Zone>[];
  String canelString = 'yet';
  LatLng latLngPassengerLocation = LatLng(0, 0);
  late LatLng latLngPassengerDestination = LatLng(0, 0);

  List<Map<String, dynamic>> routeSteps = [];
  String currentInstruction = "";
  int currentStepIndex = 0;

  @override
  void onClose() {
    print("--- Controller is closing. Cleaning up listener. ---");

    // This will stop the listener when you leave the page
    _posSub?.cancel();
    _navigationTimer?.cancel();
    // It's also good practice to dispose the map controller
    mapController?.dispose();

    super.onClose();
  }

  void onMapCreated(GoogleMapController controller) async {
    myLocation = Get.find<LocationController>().myLocation;
    // myLocation = myLocation;
    mapController = controller;
    controller.getVisibleRegion();
    // LatLngBounds bounds = await controller.getVisibleRegion();
    controller.animateCamera(
      CameraUpdate.newLatLng(Get.find<LocationController>().myLocation),
    );
    update();
    // Set up a timer or interval to trigger the marker update every 3 seconds.
    timer = Timer.periodic(const Duration(seconds: 1), (_) {
      updateMarker();
    });
  }

  void changeStatusDriver() {
    status = 'On';
    update();
  }

  void changeDriverEndPage() {
    remainingTimeTimerRideBegin < 60 ? driverEndPage = 160 : 100;
    update();
  }

  takeSnapMap() {
    mapController!.takeSnapshot();
  }

  @override
  void dispose() {
    mapController!.dispose();
    super.dispose();
  }

  Future openGoogleMapFromDriverToPassenger() async {
    var endLat = latLngPassengerLocation.latitude;
    var endLng = latLngPassengerLocation.longitude;

    var startLat = Get.find<LocationController>().myLocation.latitude;
    var startLng = Get.find<LocationController>().myLocation.longitude;

    String url =
        'https://www.google.com/maps/dir/$startLat,$startLng/$endLat,$endLng/&directionsmode=driving';
    if (await canLaunchUrl(Uri.parse(url))) {
      await launchUrl(Uri.parse(url));
    } else {
      throw 'Could not launch google maps';
    }
  }

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

  void changeRideToBeginToPassenger() {
    isRideBegin = true;
    passengerInfoWindowHeight = Get.height * .22;
    update();
  }

  cancelTripFromDriverAfterApplied() async {
    if (formKeyCancel.currentState!.validate()) {
      box.write(BoxName.statusDriverLocation, 'off');
      Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
        "Cancel Trip from driver",
        "Trip Cancelled from driver. We are looking for a new driver. Please wait."
            .tr,
        tokenPassenger,
        [],
        'cancel.wav',
      );
      await CRUD().post(
          link: "${AppLink.seferCairoServer}/ride/rides/update.php",
          payload: {
            "id": (rideId).toString(), // Convert to String
            "status": 'CancelFromDriverAfterApply'
          });
      CRUD().postFromDialogue(
          link: '${AppLink.seferCairoServer}/driver_order/add.php',
          payload: {
            'driver_id': box.read(BoxName.driverID).toString(),
            // box.read(BoxName.driverID).toString(),
            'order_id': (rideId).toString(),
            'status': 'CancelFromDriverAfterApply'
          });
      await CRUD().post(
          link:
              "${AppLink.seferCairoServer}/ride/cancelRide/addCancelTripFromDriverAfterApplied.php",
          payload: {
            "order_id": (rideId).toString(),
            "driver_id": box.read(BoxName.driverID).toString(),
            "status": 'reject After Applied',
            "notes": (cancelTripCotroller.text).toString()
          });
      if (AppLink.endPoint != AppLink.seferCairoServer) {
        CRUD()
            .post(link: "${AppLink.endPoint}/ride/rides/update.php", payload: {
          "id": (rideId).toString(), // Convert to String
          "status": 'CancelFromDriverAfterApply'
        });
        CRUD().postFromDialogue(
            link: '${AppLink.endPoint}/driver_order/add.php',
            payload: {
              'driver_id': box.read(BoxName.driverID).toString(),
              // box.read(BoxName.driverID).toString(),
              'order_id': (rideId).toString(),
              'status': 'CancelFromDriverAfterApply'
            });
        CRUD().post(
            link:
                "${AppLink.endPoint}/ride/cancelRide/addCancelTripFromDriverAfterApplied.php",
            payload: {
              "order_id": (rideId).toString(),
              "driver_id": box.read(BoxName.driverID).toString(),
              "status": 'reject After Applied',
              "notes": (cancelTripCotroller.text).toString()
            });
      }

      sql.insertData({
        'order_id': (rideId),
        'created_at': DateTime.now().toString(),
        'driver_id': box.read(BoxName.driverID).toString(),
      }, TableName.driverOrdersRefuse);
      box.write(BoxName.rideStatus, 'Cancel');
      Log.print('rideStatus from map 240 : ${box.read(BoxName.rideStatus)}');
      Get.find<HomeCaptainController>().getRefusedOrderByCaptain();
      Get.offAll(() => HomeCaptain());
    }
  }

  void startTimerToShowPassengerInfoWindowFromDriver() async {
    if (box.read(BoxName.rideStatus) == 'Begin') {
      Log.print('rideStatus from map 248 : ${box.read(BoxName.rideStatus)}');
      isPassengerInfoWindow = false;
    } else {
      isPassengerInfoWindow = true;
      for (int i = 0; i <= int.parse(durationToPassenger); i++) {
        await Future.delayed(const Duration(seconds: 1));
        progressToPassenger = i / int.parse(durationToPassenger);
        remainingTimeToPassenger = int.parse(durationToPassenger) - i;
        if (remainingTimeToPassenger == 0) {
          isBtnRideBegin = true;
          update();
        }

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

        update();
      }
    }

    // update();
    // startTimerToShowDriverToPassengerDuration();
  }

  String stringRemainingTimeToPassenger = '';

  String stringRemainingTimeWaitingPassenger = '';

  void startTimerToShowDriverWaitPassengerDuration() async {
    for (int i = 0; i <= timeWaitingPassenger * 60; i++) {
      await Future.delayed(const Duration(seconds: 1));
      progressInPassengerLocationFromDriver = i / (timeWaitingPassenger * 60);
      remainingTimeInPassengerLocatioWait = (timeWaitingPassenger * 60) - i;
      if (isRideBegin == true) {
        remainingTimeInPassengerLocatioWait = 0;
        update();
      }
      if (remainingTimeInPassengerLocatioWait == 0) {
        isdriverWaitTimeEnd = true;
        update();
      }
      'remainingTimeInPassengerLocatioWait $remainingTimeInPassengerLocatioWait';

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

      update();
    }
  }

  void driverGoToPassenger() async {
    changeRideToBeginToPassenger();
    box.write(BoxName.rideStatus, 'Applied');
    Log.print('rideStatus from map 304 : ${box.read(BoxName.rideStatus)}');
    update();
    await CRUD().post(
        link: "${AppLink.seferCairoServer}/ride/rides/update.php",
        payload: {
          'id': (rideId),
          'driverGoToPassengerTime': DateTime.now().toString(),
          'status': 'Applied'
        });

    // Get.find<HomeCaptainController>().changeToAppliedRide('Applied');

    Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
        'Driver Is Going To Passenger'.tr,
        box.read(BoxName.nameDriver).toString(), //todo name driver
        tokenPassenger,
        [],
        'start.wav');
  }

  bool isSocialPressed = false;
  driverCallPassenger() async {
    String scam = await getDriverScam();
    if (scam != 'failure') {
      if (int.parse(scam) > 3) {
        box.write(BoxName.statusDriverLocation, 'on');
        Get.find<LocationController>().stopLocationUpdates();
        await CRUD().post(link: AppLink.addNotificationCaptain, payload: {
          'driverID': box.read(BoxName.driverID),
          'title': 'scams operations'.tr,
          'body':
              'you have connect to passengers and let them cancel the order'.tr,
        });
      } else if (isSocialPressed == true) {
        box.write(BoxName.statusDriverLocation, 'off');
        await CRUD().post(link: AppLink.addDriverScam, payload: {
          'driverID': box.read(BoxName.driverID),
          'passengerID': passengerId,
          'rideID': rideId,
          'isDriverCalledPassenger': '$isSocialPressed'
        });
      }
    }
  }

  Future<String> getDriverScam() async {
    var res = await CRUD().post(link: AppLink.getDriverScam, payload: {
      'driverID': box.read(BoxName.driverID),
    });
    if (res == 'failure') {
      box.write(BoxName.statusDriverLocation, 'off');
      return '0';
    }
    var d = jsonDecode(res);
    return d['message'][0]['count'];
  }

  void startRideFromStartApp() {
    // if (box.read(BoxName.rideStatus) == 'Begin') {
    changeRideToBeginToPassenger();
    isPassengerInfoWindow = false;
    isRideStarted = true;
    isRideFinished = false;
    remainingTimeInPassengerLocatioWait = 0;
    timeWaitingPassenger = 0;
    box.write(BoxName.statusDriverLocation, 'on');
    update();
    // }

    // rideIsBeginPassengerTimer();
  }

  Position? currentPosition;
  startRideFromDriver() async {
    double _distance =
        await calculateDistanceBetweenDriverAndPassengerLocation();

    if (_distance < 400) {
      changeRideToBeginToPassenger();
      isPassengerInfoWindow = false;
      isRideStarted = true;
      isRideFinished = false;
      remainingTimeInPassengerLocatioWait = 0;
      timeWaitingPassenger = 0;
      box.write(BoxName.statusDriverLocation, 'on');

      // // ابدأ التتبع الحيّ لخطوات الملاحة
      await startListeningStepNavigation();
      // box.write(BoxName.rideStatus, 'Begin'); //
      // todo ride details
      // Get.find<HomeCaptainController>().changeToAppliedRide('Begin');
      box.write(BoxName.rideStatus, 'Begin');
      Log.print('rideStatus from map 399  : ${box.read(BoxName.rideStatus)}');
      // Get.find<HomeCaptainController>().update();
      update();
      await CRUD().post(link: AppLink.updateRides, payload: {
        'id': (rideId),
        'rideTimeStart': DateTime.now().toString(),
        'status': 'Begin',
      });
      CRUD().post(link: AppLink.addDriverOrder, payload: {
        'driver_id': box.read(BoxName.driverID).toString(),
        'order_id': (rideId).toString(),
        'status': 'Begin'
      });
      final fcm = Get.isRegistered<FirebaseMessagesController>()
          ? Get.find<FirebaseMessagesController>()
          : Get.put(FirebaseMessagesController());
      fcm.sendNotificationToDriverMAP(
          'Trip is Begin'.tr,
          box.read(BoxName.nameDriver).toString(),
          tokenPassenger,
          [],
          'start.wav');
      rideIsBeginPassengerTimer();

      update();
    } else {
      Get.back();
      MyDialog().getDialog('Your are far from passenger location'.tr,
          'go to your passenger location before\nPassenger cancel trip'.tr, () {
        Get.back();
      });
    }
  }

  calculateDistanceInMeter(LatLng prev, LatLng current) async {
    double distance2 = Geolocator.distanceBetween(
      prev.latitude,
      prev.longitude,
      current.latitude,
      current.longitude,
    );
    return distance2;
  }

  double speedoMeter = 0;
  void updateLocation() async {
    try {
      for (var i = 0; i < remainingTimeTimerRideBegin; i++) {
        await Future.delayed(const Duration(seconds: 1));

        mapController!.animateCamera(
          CameraUpdate.newCameraPosition(
            CameraPosition(
              bearing: Get.find<LocationController>().heading,
              target: myLocation,
              zoom: 17, // Adjust zoom level as needed
            ),
          ),
        );
        // });
        update();
      }

      // Stop listening after ride finishes
      if (!isRideBegin) {}
    } catch (error) {
      debugPrint('Error listening to GPS: $error');
      // Handle GPS errors gracefully
    }

    // Periodically call updateLocation again
    await Future.delayed(const Duration(seconds: 1));
    updateLocation();
  }

  calculateDistanceBetweenDriverAndPassengerLocation() async {
    Get.put(LocationController());
    var res = await CRUD().get(
        link: AppLink.getLatestLocationPassenger,
        payload: {'rideId': (rideId)});
    if (res != 'failure') {
      var passengerLatestLocationString = jsonDecode(res)['message'];

      double distance2 = Geolocator.distanceBetween(
        double.parse(passengerLatestLocationString[0]['lat'].toString()),
        double.parse(passengerLatestLocationString[0]['lng'].toString()),
        Get.find<LocationController>().myLocation.latitude,
        Get.find<LocationController>().myLocation.longitude,
      );
      return distance2;
    } else {
      double distance2 = Geolocator.distanceBetween(
        latLngPassengerLocation.latitude,
        latLngPassengerLocation.longitude,
        Get.find<LocationController>().myLocation.latitude,
        Get.find<LocationController>().myLocation.longitude,
      );
      return distance2;
    }
  }

  addWaitingTimeCostFromPassengerToDriverWallet() async {
    double distance2 =
        await calculateDistanceBetweenDriverAndPassengerLocation();

    if (distance2 > 60) {
      MyDialog().getDialog('Your are far from passenger location'.tr,
          'go to your passenger location before\nPassenger cancel trip'.tr, () {
        Get.back();
      });
    } else {
      double costOfWaiting5Minute = box.read(BoxName.countryCode) == 'Egypt'
          ? (distanceBetweenDriverAndPassengerWhenConfirm * .08) + (5 * 1)
          : (distanceBetweenDriverAndPassengerWhenConfirm * .06) +
              (5 * .06); //for Eygpt other like jordan .06 per minute
      await CRUD().post(link: AppLink.updateRides, payload: {
        'id': (rideId),
        'rideTimeStart': DateTime.now().toString(),
        'status': 'CancelAfterWait',
      });
      CRUD().post(link: AppLink.addDriverOrder, payload: {
        'driver_id': box.read(BoxName.driverID).toString(),
        'order_id': (rideId).toString(),
        'status': 'CancelAfterWait'
      });

      if (AppLink.endPoint != AppLink.seferCairoServer) {
        CRUD().post(link: "${AppLink.endPoint}/rides/update.php", payload: {
          'id': (rideId),
          'rideTimeStart': DateTime.now().toString(),
          'status': 'CancelAfterWait',
        });
        CRUD().post(link: "${AppLink.endPoint}/rides/update.php", payload: {
          'driver_id': box.read(BoxName.driverID).toString(),
          'order_id': (rideId).toString(),
          'status': 'CancelAfterWait'
        });
      }
      var paymentTokenWait =
          await generateTokenDriver(costOfWaiting5Minute.toString());
      var res = await CRUD().post(link: AppLink.addDrivePayment, payload: {
        'rideId': (rideId),
        'amount': (costOfWaiting5Minute.toString()),
        'payment_method': 'wait-cancel',
        'passengerID': (passengerId),
        'token': paymentTokenWait,
        'driverID': box.read(BoxName.driverID).toString(),
      });
      var paymentTokenWait1 =
          await generateTokenDriver(costOfWaiting5Minute.toString());
      var res1 =
          await CRUD().post(link: AppLink.addDriversWalletPoints, payload: {
        'paymentID': 'rideId${(rideId)}',
        'amount': (costOfWaiting5Minute).toStringAsFixed(0),
        'paymentMethod': 'wait',
        'token': paymentTokenWait1,
        'driverID': box.read(BoxName.driverID).toString(),
      });
      if (res != 'failure') {
        Get.snackbar(
          'You will get cost of your work for this trip'.tr,
          '${'you gain'.tr} $costOfWaiting5Minute \$${' in your wallet'.tr}',
          backgroundColor: AppColor.deepPurpleAccent,
        );
      }
      var paymentTokenWaitPassenger1 =
          await generateTokenPassenger((costOfWaiting5Minute * -1).toString());
      await CRUD().post(link: AppLink.addPassengersWallet, payload: {
        'passenger_id': (passengerId),
        'balance': (costOfWaiting5Minute * -1).toString(),
        'token': paymentTokenWaitPassenger1,
      });
      box.write(BoxName.statusDriverLocation, 'off');
      Get.offAll(HomeCaptain());
    }
  }

  Future<void> finishRideFromDriver() async {
    // double distanceToDestination = Geolocator.distanceBetween(
    //   latLngPassengerDestination.latitude,
    //   latLngPassengerDestination.longitude,
    //   Get.find<LocationController>().myLocation.latitude,
    //   Get.find<LocationController>().myLocation.longitude,
    // );
    final originalDistanceM = double.parse(distance.toString()) * 1000;

    // 2. احسب المسافة التي قطعها السائق حتى الآن
    final movedDistanceM = Geolocator.distanceBetween(
      Get.find<LocationController>().myLocation.latitude,
      Get.find<LocationController>().myLocation.longitude,
      latLngPassengerLocation.latitude,
      latLngPassengerLocation.longitude,
    );
    // originalDistanceM - distanceToDestination;

    // 3. عتبة ثلث المسافة
    final oneThirdDistanceM = originalDistanceM / 5;

    // Logging للتتبع
    Log.print('originalDistanceM: $originalDistanceM');
    // Log.print('distanceToDestinationM: $distanceToDestination');
    Log.print('movedDistanceM: $movedDistanceM');
    Log.print('oneThirdDistanceM: $oneThirdDistanceM');

    // 4. إذا لم يقطع السائق ثلث المسافة، نعرض التأكيد
    if (movedDistanceM > oneThirdDistanceM) {
      MyDialog().getDialog(
        'Are you sure to exit ride?'.tr,
        '',
        () {
          Get.back();
          finishRideFromDriver1();
        },
      );
    } /////

    else {
      final textToSpeechController = Get.put(TextToSpeechController());
      MyDialog().getDialog(
        "You haven't moved sufficiently!".tr,
        '',
        () => Get.back(),
      );
      await textToSpeechController
          .speakText("You haven't moved sufficiently!".tr);
    }
  }

  String paymentToken = '';
  Future<String> generateTokenDriver(String amount) async {
    var res =
        await CRUD().postWallet(link: AppLink.addPaymentTokenDriver, payload: {
      'driverID': box.read(BoxName.driverID).toString(),
      'amount': amount.toString(),
    });
    var d = (res);
    return d['message'];
  }

  String paymentTokenPassenger = '';
  Future<String> generateTokenPassenger(String amount) async {
    var res = await CRUD()
        .postWallet(link: AppLink.addPaymentTokenPassenger, payload: {
      'passengerId': passengerId,
      'amount': amount.toString(),
    });
    var d = (res);
    return d['message'];
  }

  void finishRideFromDriver1() async {
    isRideFinished = true;
    isRideStarted = false;
    isPriceWindow = false;
    box.write(BoxName.rideStatus, 'Finished');
    Log.print('rideStatus from map 664 : ${box.read(BoxName.rideStatus)}');

    // Calculate totalCost more concisely
    if (price < 16000) {
      totalCost = (carType == 'Comfort' ||
              carType == 'Mishwar Vip' ||
              carType == 'Lady')
          ? '20000'
          : '16000';
    } else if (price < double.parse(totalPricePassenger)) {
      totalCost = totalPricePassenger;
    } else {
      totalCost = (carType == 'Comfort' ||
              carType == 'Mishwar Vip' ||
              carType == 'Lady')
          ? price.toStringAsFixed(2)
          : totalPricePassenger;
    }
    paymentAmount = totalCost;
    box.write(BoxName.statusDriverLocation, 'off');

    // Prepare data for API calls
    final nowString = DateTime.now().toString();
    final basePayload = {
      'id': (rideId),
      'rideTimeFinish': nowString,
      'status': 'Finished',
      'price': totalCost,
    };
    final driverOrderPayload = {
      'order_id': (rideId.toString()),
      'status': 'Finished'
    };

    // List to hold all asynchronous operations
    List<Future<dynamic>> futures = [];

    // API calls that can run in parallel
    futures.add(CRUD().post(
      link: "${AppLink.seferCairoServer}/ride/rides/update.php",
      payload: basePayload,
    ));
    futures.add(CRUD().post(
      link: "${AppLink.seferCairoServer}/ride/driver_order/update.php",
      payload: driverOrderPayload,
    ));

    // Wallet transactions (can potentially be parallelized if independent)
    if (walletChecked == 'true') {
      paymentToken = await generateTokenPassenger(
          ((-1) * double.parse(paymentAmount)).toString());
      futures
          .add(CRUD().postWallet(link: AppLink.addPassengersWallet, payload: {
        'passenger_id': (passengerId),
        'balance': ((-1) * double.parse(paymentAmount)).toString(),
        'token': paymentToken,
      }));
    }

    paymentToken = await generateTokenDriver(paymentAmount.toString());
    futures.add(CRUD().postWallet(link: AppLink.addDrivePayment, payload: {
      'rideId': (rideId),
      'amount': paymentAmount,
      'payment_method':
          walletChecked == 'true' ? "${paymentMethod}Ride" : paymentMethod,
      'passengerID': (passengerId),
      'token': paymentToken,
      'driverID': box.read(BoxName.driverID).toString(),
    }));

    if (double.parse(passengerWalletBurc) < 0) {
      final paymentToken1 = await generateTokenPassenger(
          ((-1) * double.parse(passengerWalletBurc)).toString());
      futures
          .add(CRUD().postWallet(link: AppLink.addPassengersWallet, payload: {
        'passenger_id': (passengerId),
        'token': paymentToken1,
        'balance': ((-1) * double.parse(passengerWalletBurc)).toString()
      }));
    }

    double pointsSubtraction = double.parse(paymentAmount) * (-1) * 0.1;
    final paymentToken2 =
        await generateTokenDriver((pointsSubtraction).toStringAsFixed(0));
    futures
        .add(CRUD().postWallet(link: AppLink.addDriversWalletPoints, payload: {
      'paymentID': 'rideId${(rideId)}',
      'amount': (pointsSubtraction).toStringAsFixed(0),
      'paymentMethod': paymentMethod,
      'token': paymentToken2,
      'driverID': box.read(BoxName.driverID).toString(),
    }));

    // Wait for all independent API calls to complete
    await Future.wait(futures);
    Get.put(DriverBehaviorController()).sendSummaryToServer(driverId, rideId);

    // Send notification (this likely depends on previous steps)
    Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
        "Driver Finish Trip".tr,
        '${'you will pay to Driver'.tr} $paymentAmount \$',
        tokenPassenger,
        [
          box.read(BoxName.driverID),
          rideId,
          box.read(BoxName.tokenDriver),
          paymentAmount.toString()
        ],
        'ding.wav');

    // Navigate to the next screen (likely depends on previous steps being done)
    Get.to(() => RatePassenger(), arguments: {
      'passengerId': passengerId,
      'rideId': rideId,
      'price': paymentAmount.toString(),
      'walletChecked': walletChecked
    });
  }
  // void finishRideFromDriver1() async {
  //   // if (carType != 'Comfort' || carType != 'Free Ride') {

  //   isRideFinished = true;
  //   isRideStarted = false;
  //   isPriceWindow = false;
  //   box.write(BoxName.rideStatus, 'Finished');
  //   // Get.find<HomeCaptainController>().changeToAppliedRide('Finished');
  //   // Get.find<HomeCaptainController>().update();
  //   totalCost = price < 20
  //       ? carType != 'Comfort' && carType != 'Mishwar Vip' && carType != 'Lady'
  //           ? '20'
  //           : '30'
  //       : price < double.parse(totalPricePassenger)
  //           ? totalPricePassenger
  //           : carType != 'Comfort' &&
  //                   carType != 'Mishwar Vip' &&
  //                   carType != 'Lady'
  //               ? totalPricePassenger
  //               : price.toStringAsFixed(2);
  //   paymentAmount = totalCost;
  //   box.write(BoxName.statusDriverLocation, 'off');
  //   // changeRideToBeginToPassenger();
  //   await CRUD().post(
  //       link: "${AppLink.seferCairoServer}/ride/rides/update.php",
  //       payload: {
  //         'id': rideId,
  //         'rideTimeFinish': DateTime.now().toString(),
  //         'status': 'Finished',
  //         'price': totalCost,
  //       });
  //   CRUD().post(
  //       link: "${AppLink.seferCairoServer}/ride/driver_order/update.php",
  //       payload: {
  //         // 'driver_id': box.read(BoxName.driverID).toString(),
  //         'order_id': rideId.toString(),
  //         'status': 'Finished'
  //       });
  //   if (AppLink.endPoint != AppLink.seferCairoServer) {
  //     CRUD().post(
  //       link: "${AppLink.endPoint}/ride/rides/update.php",
  //       payload: {
  //         'id': rideId,
  //         'rideTimeFinish': DateTime.now().toString(),
  //         'status': 'Finished',
  //         'price': totalCost,
  //       },
  //     );
  //     CRUD().post(
  //         link: "${AppLink.endPoint}/ride/driver_order/update.php",
  //         payload: {
  //           // 'driver_id': box.read(BoxName.driverID).toString(),
  //           'order_id': rideId.toString(),
  //           'status': 'Finished'
  //         });
  //   }
  //   if (walletChecked == 'true') {
  //     paymentToken = await generateTokenPassenger(
  //         ((-1) * double.parse(paymentAmount)).toString());
  //     await CRUD().post(link: AppLink.addPassengersWallet, payload: {
  //       'passenger_id': passengerId,
  //       'balance': ((-1) * double.parse(paymentAmount)).toString(),
  //       'token': paymentToken,
  //     });
  //   }
  //   paymentToken = await generateTokenDriver(paymentAmount.toString());
  //   await CRUD().post(link: AppLink.addDrivePayment, payload: {
  //     'rideId': rideId,
  //     'amount': paymentAmount,
  //     'payment_method':
  //         walletChecked == 'true' ? "${paymentMethod}Ride" : paymentMethod,
  //     'passengerID': passengerId,
  //     'token': paymentToken,
  //     'driverID': box.read(BoxName.driverID).toString(),
  //   });
  //   if (double.parse(passengerWalletBurc) < 0) {
  //     // for zero passenger
  //     var paymentToken1 = await generateTokenPassenger(
  //         ((-1) * double.parse(passengerWalletBurc)).toString());
  //     await CRUD().post(link: AppLink.addPassengersWallet, payload: {
  //       'passenger_id': passengerId,
  //       'token': paymentToken1,
  //       'balance': ((-1) * double.parse(passengerWalletBurc)).toString()
  //     });
  //   }

  //   double pointsSubtraction = 0;
  //   pointsSubtraction =
  //       double.parse(paymentAmount) * (-1) * .08; //for 300 from 3000
  //   var paymentToken2 =
  //       await generateTokenDriver((pointsSubtraction).toStringAsFixed(0));
  //   var res = await CRUD().post(link: AppLink.addDriversWalletPoints, payload: {
  //     'paymentID': 'rideId$rideId',
  //     'amount': (pointsSubtraction).toStringAsFixed(0),
  //     'paymentMethod': paymentMethod,
  //     'token': paymentToken2,
  //     'driverID': box.read(BoxName.driverID).toString(),
  //   });
  //   Future.delayed(const Duration(milliseconds: 300));
  //    Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
  //       "Driver Finish Trip".tr,
  //       '${'you will pay to Driver'.tr} $paymentAmount \$',
  //       tokenPassenger,
  //       [
  //         box.read(BoxName.driverID),
  //         rideId,
  //         box.read(BoxName.tokenDriver),
  //         // carType == 'Comfort' || carType == 'Mishwar Vip'
  //         //     ? price.toStringAsFixed(2)
  //         //     : totalPassenger
  //         paymentAmount.toString()
  //       ],
  //       'ding.wav');
  //   Get.to(() => RatePassenger(), arguments: {
  //     'passengerId': passengerId,
  //     'rideId': rideId,
  //     'price': paymentAmount.toString(), //price
  //     'walletChecked': walletChecked
  //   });
  //   // Get.back();
  // }

  void cancelCheckRideFromPassenger() async {
    var res = await CRUD().get(
        link: "${AppLink.endPoint}/ride/driver_order/getOrderCancelStatus.php",
        payload: {
          'order_id': (rideId),
        }); //.then((value) {
    var response = jsonDecode(res);
    canelString = response['data']['status'];
    update();
    if (canelString == 'Cancel') {
      remainingTimeTimerRideBegin = 0;
      remainingTimeToShowPassengerInfoWindowFromDriver = 0;
      remainingTimeToPassenger = 0;
      isRideStarted = false;
      isRideFinished = false;
      isPassengerInfoWindow = false;
      clearPolyline();
      update();
      MyDialog().getDialog(
        'Order Cancelled'.tr,
        'Order Cancelled by Passenger'.tr,
        () {
          Get.offAll(HomeCaptain());
        },
      );
    }
  }

  int rideTimerFromBegin = 0;
  double price = 0;
  DateTime currentTime = DateTime.now();

  /// أثناء الرحلة: نعرض السعر لحظياً بدون مضاعفة العمولة في كل ثانية.
  /// - نستخدم سعر الدقيقة حسب الوقت، مع قواعد الرحلات البعيدة:
  ///   >25كم أو >35كم => دقيقة = 600، سقف 60 دقيقة، ومع >35كم عفو 10 دقائق.
  /// - سرعة طويلة: لو المسافة المخططة > 40كم نستخدم 2600 ل.س/كم للـ Speed،
////  ونطبق نفس نسبة التخفيض على Comfort/Electric/Van.
  /// - نضيف فقط "الزيادة" فوق التسعيرة المقتبسة (وقت زائد + كم زائد).
  /// - نعكس العمولة kazán مرة واحدة على الزيادة (وليس كل ثانية).

  void rideIsBeginPassengerTimer() async {
    // === مراجع عامة ===
    final hc = Get.find<HomeCaptainController>();
    final loc = Get.find<LocationController>();

    // أسعار/كم من السيرفر
    final double perKmSpeedBase = hc.speedPrice; // مثال: 2900
    final double perKmComfortRaw = hc.comfortPrice; // مثال: 3600
    final double perKmDelivery = hc.deliveryPrice; // للدليفري
    final double perKmVanRaw = hc.familyPrice; // فان
    const double electricUpliftKm = 400; // كهرباء = كومفورت + 400/كم
    final double perKmElectricRaw = perKmComfortRaw + electricUpliftKm;

    // أسعار الدقيقة (ل.س/دقيقة)
    final double perMinNature = hc.naturePrice; // طبيعي
    final double perMinLate = hc.latePrice; // ليل
    final double perMinHeavy = hc.heavyPrice; // ذروة

    // Long/بعيد
    const double longSpeedThresholdKm = 40.0;
    const double longSpeedPerKm = 2600.0;

    const double mediumDistThresholdKm = 25.0; // >25كم
    const double longDistThresholdKm = 35.0; // >35كم
    const double longTripPerMin = 600.0;
    const int minuteCapMedium = 60; // سقف 60 دقيقة
    const int minuteCapLong = 60; // سقف 60 دقيقة
    const int freeMinutesLong = 10; // عفو 10 دقائق عند >35كم

    const double extraReduction100 = 0.07; // +7% فوق تخفيض >40كم عند >100كم
    const double maxReductionCap = 0.35; // سقف إجمالي للتخفيض

    // ——— الأساسات المقتبسة من شاشة التسعير ———
    final double basePassengerQuote = double.tryParse(totalCost) ?? 0.0;

    // الدقائق المقتبسة (من نفس المصدر الذي تستخدمه مسبقًا)
    final int quotedMinutes =
        int.tryParse(duration) ?? int.tryParse(durationOfRideValue) ?? 0;

    // ——— المسافة المخططة من Notification/OnInit ———
    // حاول أولًا من متغيّر الرحلة (تمريره عند onInit من النوتيفيكيشن):
    double plannedKm = 0.0;
    try {
      // أمثلة أسماء: غيّر وفق ما عندك
      // 1) إن كانت محفوظة في هذا الكنترولر: this.plannedDistanceKm
      plannedKm = (int.parse(distance) as num).toDouble();
    } catch (_) {}
    final double startKm = loc.totalDistance;
    if (plannedKm <= 0) {
      // fallback ثالث: خذ المسافة الحيّة وقت البدء كأساس
      plannedKm = (startKm > 0) ? startKm : 0.0;
    }

    // ——— سياق المطار (لا نضيف 20,000 هنا مرة ثانية) ———
    bool _isAirport(String s) =>
        s.toLowerCase().contains('airport') ||
        s.contains('مطار') ||
        s.contains('المطار');
    final bool airportCtx =
        _isAirport(startNameLocation) || _isAirport(endNameLocation);

    // عمولة الراكب (kazan ٪)
    final double kazanPct = (double.tryParse(kazan) ?? 0.0) / 100.0;

    // ——— أدوات ———
    double _perMinuteByTime(DateTime now) {
      final h = now.hour;
      if (airportCtx) return perMinLate; // مطار = دقيقة ليل (مثل منطقك القديم)
      if (h >= 21 || h < 1) return perMinLate; // ليل
      if (h >= 14 && h <= 17) return perMinHeavy; // ذروة
      return perMinNature; // طبيعي
    }

    bool _isLongSpeed(double km) => km > longSpeedThresholdKm;

    double _distanceReductionPct(double km) {
      double r40 = 0.0;
      if (perKmSpeedBase > 0) {
        r40 = (1.0 - (longSpeedPerKm / perKmSpeedBase))
            .clamp(0.0, maxReductionCap);
      }
      if (km > 100.0)
        return (r40 + extraReduction100).clamp(0.0, maxReductionCap);
      if (km > 40.0) return r40;
      return 0.0;
    }

    // فلترة اهتزاز GPS
    const double jitterMeters = 10.0;
    double lastKmForNoise = startKm;

    // تحديث كل 5 ثواني
    final int loopCapSec = (quotedMinutes + 3600) * 60; // أمان

    for (int sec = 0; sec <= loopCapSec; sec += 5) {
      await Future.delayed(const Duration(seconds: 5));
      final now = DateTime.now();

      // كم حي (مع فلترة الاهتزاز)
      double liveKm = loc.totalDistance;
      final double deltaMeters = (liveKm - lastKmForNoise) * 1000.0;
      if (deltaMeters < jitterMeters) {
        liveKm = lastKmForNoise;
      } else {
        lastKmForNoise = liveKm;
      }

      // كم معتمد لقواعد التسعير
      final double plannedForRulesKm = (plannedKm > 0) ? plannedKm : liveKm;

      // LongSpeed لسعر/كم Speed
      final bool isLong = _isLongSpeed(plannedForRulesKm);

      // نسبة التخفيض للفئات الأخرى (Comfort/Electric/Van) في كل الأوقات
      final double reductionPct = _distanceReductionPct(plannedForRulesKm);

      // سعر/كم فعّال لكل فئة
      final double perKmSpeed = isLong ? longSpeedPerKm : perKmSpeedBase;
      final double perKmBalash = (perKmSpeed - 500).clamp(0, double.infinity);
      final double perKmComfort =
          (perKmComfortRaw * (1.0 - reductionPct)).clamp(0, double.infinity);
      final double perKmElectric =
          (perKmElectricRaw * (1.0 - reductionPct)).clamp(0, double.infinity);
      final double perKmVan =
          (perKmVanRaw * (1.0 - reductionPct)).clamp(0, double.infinity);

      final double perKmForType = () {
        switch (carType) {
          case 'Speed':
            return perKmSpeed;
          case 'Awfar Car':
            return perKmBalash;
          case 'Comfort':
          case 'Mishwar Vip':
          case 'RayehGaiComfort':
          case 'Lady':
            return perKmComfort;
          case 'Electric':
            return perKmElectric;
          case 'Van':
            return perKmVan;
          case 'Delivery':
            return perKmDelivery;
          default:
            return perKmSpeed;
        }
      }();

      // قواعد الدقيقة (تطبّق على كل الأوقات بما فيها المطار)
      double perMinEff = _perMinuteByTime(now);
      int capMinutes = 1 << 30; // لا سقف افتراضيًا
      int freeMinutes = 0;

      if (plannedForRulesKm > longDistThresholdKm) {
        perMinEff = longTripPerMin; // 600/د
        capMinutes = minuteCapLong; // سقف 60
        freeMinutes = freeMinutesLong; // عفو 10
      } else if (plannedForRulesKm > mediumDistThresholdKm) {
        perMinEff = longTripPerMin; // 600/د
        capMinutes = minuteCapMedium; // سقف 60
      }

      // دقائق منقضية
      final int elapsedMinutes = (sec ~/ 60);

      // دقائق إضافية فوق المقتبس (مع السقف/العفو)
      int extraMinutes = 0;
      final int rawExtra = elapsedMinutes - quotedMinutes - freeMinutes;
      if (rawExtra > 0) {
        extraMinutes = rawExtra;
        if (capMinutes < (1 << 30)) {
          final int maxBill = (capMinutes - quotedMinutes - freeMinutes);
          if (extraMinutes > maxBill)
            extraMinutes = maxBill.clamp(0, extraMinutes);
        }
      }

      // كيلومترات إضافية: إن لم يكن لدينا plannedKm «حقيقي»، نقيس على لحظة البدء
      double extraKm = liveKm - plannedForRulesKm;
      if (plannedKm <= 0) {
        extraKm = (liveKm - startKm);
      }
      if (extraKm < 0) extraKm = 0;

      // زيادات قبل العمولة (بدون إضافة مطار ثابتة — فهي مضافة في التسعير الأولي)
      final double extraBefore =
          (extraMinutes * perMinEff) + (extraKm * perKmForType);

      // السعر المعروض = المقتبس + الزيادات * (1 + kazan)
      price = basePassengerQuote + (extraBefore * (1.0 + kazanPct));

      // تحديث واجهة
      speed = loc.speed * 3.6;
      remainingTimeTimerRideBegin =
          (quotedMinutes * 60 - sec).clamp(0, 1 << 30);
      progressTimerRideBegin = (quotedMinutes == 0)
          ? 0
          : (sec / (quotedMinutes * 60)).clamp(0.0, 1.0);
      remainingTimeTimerRideBegin < 60 ? driverEndPage = 160 : 100;

      updateMarker();
      update();
    }
  } //   int durationOfRide = int.parse(durationOfRideValue);
  //   double latePrice = Get.find<HomeCaptainController>().latePrice;
  //   update();
  //   int infinity = 40000;
  //   if (carType == 'Comfort' ||
  //       carType == 'Mishwar Vip' ||
  //       carType == 'RayehGaiComfort') {
  //     durationOfRide = infinity;
  //     update();
  //   }

  //   price = double.parse(totalCost);

  //   for (int i = 0; i <= durationOfRide; i++) {
  //     await Future.delayed(const Duration(seconds: 1));
  //     recentDistanceToDash = Get.find<LocationController>().totalDistance;
  //     // rideTimerFromBegin = i;
  //     if (int.parse(duration) + 300 > i) {
  //       price = double.parse(totalCost);
  //     } else {
  //       if (startNameLocation.toLowerCase().contains('airport') ||
  //           endNameLocation.toLowerCase().contains('airport') ||
  //           startNameLocation.contains('مطار') ||
  //           startNameLocation.contains('المطار') ||
  //           endNameLocation.contains('مطار') ||
  //           endNameLocation.contains('المطار')) {
  //         price = carType == 'Comfort' // || carType == 'Free Ride'
  //             ? price + ((i ~/ 60) - int.parse(duration)) * latePrice
  //             : carType == 'Lady'
  //                 ? price + ((i ~/ 60) - int.parse(duration)) * latePrice
  //                 : carType == 'RayehGaiComfort'
  //                     ? (i ~/ 60) * latePrice +
  //                         (recentDistanceToDash *
  //                             Get.find<HomeCaptainController>().comfortPrice)
  //                     : (i ~/ 60) * latePrice +
  //                         (recentDistanceToDash *
  //                             Get.find<HomeCaptainController>().mashwariPrice);
  //       } else if (currentTime.hour >= 21 && currentTime.hour < 0) {
  //         price = carType == 'Comfort' // || carType == 'Free Ride'
  //             ? price + ((i ~/ 60) - int.parse(duration)) * latePrice
  //             : carType == 'Lady'
  //                 ? price + ((i ~/ 60) - int.parse(duration)) * latePrice
  //                 : carType == 'RayehGaiComfort'
  //                     ? (i ~/ 60) * latePrice +
  //                         (recentDistanceToDash *
  //                             Get.find<HomeCaptainController>().comfortPrice)
  //                     : (i ~/ 60) * latePrice +
  //                         (recentDistanceToDash *
  //                             Get.find<HomeCaptainController>().mashwariPrice);
  //       } else if (currentTime.hour >= 1 && currentTime.hour < 5) {
  //         if (startNameLocation.contains('club') ||
  //             startNameLocation.contains('nightclub') ||
  //             startNameLocation.contains('ديسكو') ||
  //             startNameLocation.contains('ملهى ليلي') ||
  //             startNameLocation.contains('Night club')) {
  //           price = carType == 'Comfort' // || carType == 'Free Ride'
  //               ? (i ~/ 60) * (latePrice + .5) * 2 +
  //                   (price) -
  //                   int.parse(duration) * (latePrice + .5) * 2
  //               : carType == 'Lady'
  //                   ? (i ~/ 60) * (latePrice + .5) * 2 +
  //                       (price) -
  //                       int.parse(duration) * (latePrice + .5) * 2
  //                   : carType == 'RayehGaiComfort'
  //                       ? (i ~/ 60) * (latePrice + .5) * 2 + (price)
  //                       : (i ~/ 60) * (latePrice + .5) * 2 + (price);
  //         }
  //         price = carType == 'Comfort' // || carType == 'Free Ride'
  //             ? (latePrice + 0.5) * ((i ~/ 60) - int.parse(duration)) + price
  //             : carType == 'Lady'
  //                 ? (latePrice + 0.5) * ((i ~/ 60) - int.parse(duration)) +
  //                     price
  //                 : carType == 'RayehGaiComfort'
  //                     ? (latePrice + 0.5) * ((i ~/ 60) - int.parse(duration)) +
  //                         price
  //                     : price;
  //       } else if (currentTime.hour >= 14 && currentTime.hour <= 17) {
  //         price = carType == 'Comfort' // || carType == 'Free Ride'
  //             ? Get.find<HomeCaptainController>().heavyPrice *
  //                     ((i ~/ 60) - int.parse(duration)) +
  //                 price -
  //                 (0.5 * int.parse(duration))
  //             : carType == 'Lady'
  //                 ? Get.find<HomeCaptainController>().heavyPrice *
  //                         ((i ~/ 60) - int.parse(duration)) +
  //                     price -
  //                     (0.5 * int.parse(duration))
  //                 : carType == 'RayehGaiComfort'
  //                     ? (i ~/ 60) *
  //                             (Get.find<HomeCaptainController>().heavyPrice) +
  //                         (recentDistanceToDash *
  //                             Get.find<HomeCaptainController>().comfortPrice)
  //                     : (i ~/ 60) *
  //                             (Get.find<HomeCaptainController>().heavyPrice) +
  //                         (recentDistanceToDash *
  //                             Get.find<HomeCaptainController>().mashwariPrice);
  //       } else {
  //         price = carType == 'Comfort' // || carType == 'Free Ride'
  //             ? (i ~/ 60) + (price) - int.parse(duration)
  //             : carType == 'Lady'
  //                 ? (i ~/ 60) + (price) - int.parse(duration)
  //                 : carType == 'RayehGaiComfort'
  //                     ? (i ~/ 60) +
  //                         (recentDistanceToDash *
  //                             Get.find<HomeCaptainController>().comfortPrice)
  //                     : (i ~/ 60) +
  //                         (recentDistanceToDash *
  //                             Get.find<HomeCaptainController>().mashwariPrice);
  //       }
  //     }

  //     // $1 for each minute + $4 for each km
  //     price = (price * double.parse(kazan)) + price; // Add 10% tax
  //     speed = Get.find<LocationController>().speed * 3.6;
  //     progressTimerRideBegin = i / durationOfRide;
  //     remainingTimeTimerRideBegin = durationOfRide - i;
  //     remainingTimeTimerRideBegin < 60 ? driverEndPage = 160 : 100;
  //     updateMarker();
  //     if (remainingTimeTimerRideBegin < 60) {
  //       // to make driver available on last 2 minute in his trip
  //       box.write(BoxName.statusDriverLocation, 'off');
  //     }
  //     int minutes = (remainingTimeTimerRideBegin / 60).floor();
  //     int seconds = remainingTimeTimerRideBegin % 60;
  //     stringRemainingTimeRideBegin =
  //         '$minutes:${seconds.toString().padLeft(2, '0')}';
  //     int minutes1 = (i / 60).floor();
  //     int seconds1 = i % 60;
  //     stringRemainingTimeRideBegin1 =
  //         '$minutes1:${seconds1.toString().padLeft(2, '0')}';
  //     update();
  //   }
  // }

  double recentDistanceToDash = 0;
  double recentAngelToMarker = 0;
  double speed = 0;
  void updateMarker() async {
    // Remove the existing marker with the ID `MyLocation`.
    markers.remove(MarkerId('MyLocation'));

    // Add a new marker with the ID `MyLocation` at the current location of the user.
    LocationController locationController = Get.find<LocationController>();
    myLocation = locationController.myLocation;

    markers.add(
      Marker(
        markerId: MarkerId('MyLocation'.tr),
        position: myLocation,
        draggable: true,
        icon: carIcon,
        rotation: locationController.heading,
        // infoWindow: const InfoWindow(
        //   title: 'Time',
        // ),
      ),
    );

    // Animate camera only once after updating the marker
    // mapController!.animateCamera(
    //   CameraUpdate.newLatLng(myLocation),
    // );
    update();
  }

  void addCustomCarIcon() {
    ImageConfiguration config = ImageConfiguration(
        size: const Size(30, 35), devicePixelRatio: Get.pixelRatio);
    BitmapDescriptor.asset(
      config,
      'assets/images/car.png',
      // mipmaps: false,
    ).then((value) {
      carIcon = value;
      update();
    });
  }

  void addCustomStartIcon() async {
// Create the marker with the resized image

    ImageConfiguration config = ImageConfiguration(
        size: const Size(30, 30), devicePixelRatio: Get.pixelRatio);
    BitmapDescriptor.asset(
      config,
      'assets/images/A.png',
    ).then((value) {
      startIcon = value;
      update();
    });
  }

  void addCustomEndIcon() {
    ImageConfiguration config = ImageConfiguration(
        size: const Size(25, 25), devicePixelRatio: Get.pixelRatio);
    BitmapDescriptor.asset(
      config,
      'assets/images/b.png',
    ).then((value) {
      endIcon = value;
      update();
    });
  }

  void addCustomPassengerIcon() {
    ImageConfiguration config = ImageConfiguration(
        size: const Size(30, 30), devicePixelRatio: Get.pixelRatio
        // scale: 1.0,
        );
    BitmapDescriptor.asset(
      config,
      'assets/images/picker.png',
    ).then((value) {
      passengerIcon = value;
      update();
    });
  }

  var activeRouteSteps = <Map<String, dynamic>>[];
  var traveledPathPoints = <LatLng>[]; // المسار المقطوع (رمادي)
  var upcomingPathPoints = <LatLng>[]; // المسار المتبقي (أزرق/أحمر)

  // --- متغيرات الأيقونات والمواقع ---
  var heading = 0.0;
  // ... يمكنك إضافة أيقونات البداية والنهاية هنا

  // --- متغيرات قياس الأداء الذكي ---
  final List<int> _performanceReadings = [];
  final int _readingsToCollect = 10; // اجمع 10 قراءات
  bool _hasMadeDecision = false;
  var updateInterval = 5.obs; // القيمة الافتراضية

  // --- متغيرات داخلية للملاحة ---
  var _stepBounds = <LatLngBounds>[];
  var _stepEndPoints = <LatLng>[];
  var _allPointsForActiveRoute = <LatLng>[];

// دالة موحّدة وقوية لجلب أي مسار
  Future<void> getRoute({
    required LatLng origin,
    required LatLng destination,
    required Color routeColor,
  }) async {
    // إظهار مؤشر التحميل لو رغبت
    // isLoading.value = true;

    var url =
        ('${AppLink.googleMapsLink}directions/json?language=ar&destination=${destination.latitude},${destination.longitude}&origin=${origin.latitude},${origin.longitude}&key=${AK.mapAPIKEY}');
    var response = await CRUD().getGoogleApi(link: url, payload: {});

    if (response == null || response['routes'].isEmpty) {
      // isLoading.value = false;
      // أظهر رسالة خطأ
      return;
    }

    _resetRouteState(); // تنظيف الحالة القديمة قبل رسم الجديد

    final route = response['routes'][0];
    final leg = route['legs'][0];

    // استخراج النقاط ورسم المسار المبدئي بالكامل
    final pointsString = route["overview_polyline"]["points"];
    _allPointsForActiveRoute = decodePolylineToLatLng(pointsString);
    upcomingPathPoints.assignAll(_allPointsForActiveRoute);

    // استخراج خطوات الملاحة
    activeRouteSteps.assignAll(List<Map<String, dynamic>>.from(leg['steps']));
    _prepareStepData(activeRouteSteps);

    // تحديث التعليمات الأولية
    if (activeRouteSteps.isNotEmpty) {
      currentInstruction =
          _parseInstruction(activeRouteSteps[0]['html_instructions']);
      Get.find<TextToSpeechController>().speakText(currentInstruction);
    }

    // تحديث الكاميرا لتناسب المسار الجديد
    final boundsData = route["bounds"];
    _fitToBounds(LatLngBounds(
      northeast: LatLng(
          boundsData['northeast']['lat'], boundsData['northeast']['lng']),
      southwest: LatLng(
          boundsData['southwest']['lat'], boundsData['southwest']['lng']),
    ));

    // isLoading.value = false;
    update(); // تحديث الواجهة مرة واحدة بعد كل العمليات
  }

  // الدالة التي يتم استدعاؤها من خدمة الموقع كل 5 ثوان (أو حسب الفترة المحددة)
  void onLocationUpdated(Position newPosition) {
    myLocation = LatLng(newPosition.latitude, newPosition.longitude);
    heading = newPosition.heading;

    // -->> منطق قياس الأداء يبدأ هنا <<--
    final stopwatch = Stopwatch()..start();

    // -->> منطق الملاحة وتحديث المسار <<--
    _onLocationTick(myLocation);

    stopwatch.stop();

    // -->> تحليل الأداء واتخاذ القرار <<--
    if (!_hasMadeDecision) {
      _performanceReadings.add(stopwatch.elapsedMilliseconds);
      if (_performanceReadings.length >= _readingsToCollect) {
        _analyzePerformance();
        _hasMadeDecision = true;
      }
    }
  }
// =================================================================
  // 3. منطق الملاحة الداخلي (Internal Navigation Logic)
  // =================================================================

  void _onLocationTick(LatLng pos) {
    if (activeRouteSteps.isEmpty || currentStepIndex >= _stepBounds.length) {
      return;
    }

    final double dToEnd =
        _distanceMeters(pos, _stepEndPoints[currentStepIndex]);
    if (dToEnd <= 35) {
      // 35 متر عتبة للوصول لنهاية الخطوة
      _advanceStep();
    }
  }

  void _advanceStep() {
    if (currentStepIndex >= _stepBounds.length - 1) {
      // وصل للنهاية
      currentInstruction = "لقد وصلت إلى وجهتك";
      return;
    }

    currentStepIndex++;
    currentInstruction = _parseInstruction(
        activeRouteSteps[currentStepIndex]['html_instructions']);
    Get.find<TextToSpeechController>().speakText(currentInstruction);

    // -->> هنا يتم تحديث لون المسار <<--
    _updateTraveledPath();

    _fitToBounds(_stepBounds[currentStepIndex],
        padding: 80); // تقريب الكاميرا على الخطوة التالية
    update();
  }

  void _updateTraveledPath() {
    // استخراج كل النقاط للخطوات التي تم اجتيازها
    List<LatLng> pointsForTraveledSteps = [];
    for (int i = 0; i < currentStepIndex; i++) {
      final stepPolyline = activeRouteSteps[i]['polyline']['points'];
      pointsForTraveledSteps.addAll(decodePolylineToLatLng(stepPolyline));
    }
    traveledPathPoints.assignAll(pointsForTraveledSteps);
  }

  void _prepareStepData(List<Map<String, dynamic>> steps) {
    _stepBounds.clear();
    _stepEndPoints.clear();

    for (final s in steps) {
      // 1. استخراج نقطة النهاية (الكود الحالي سليم)
      final end = s['end_location'];
      _stepEndPoints.add(LatLng(
        (end['lat'] as num).toDouble(),
        (end['lng'] as num).toDouble(),
      ));

      // 2. فك تشفير البوليلاين الخاص بالخطوة وتحويله إلى LatLng
      // -->> هنا تم التصحيح <<--
      List<LatLng> pts = decodePolyline(s['polyline']['points'])
          .map((point) => LatLng(point[0].toDouble(), point[1].toDouble()))
          .toList();

      // أضف نقاط البداية والنهاية إذا لم تكن موجودة في البوليلاين لضمان دقة الحدود
      if (pts.isNotEmpty) {
        final start = s['start_location'];
        final startLatLng = LatLng(
            (start['lat'] as num).toDouble(), (start['lng'] as num).toDouble());
        if (pts.first != startLatLng) {
          pts.insert(0, startLatLng);
        }
      }

      _stepBounds.add(_boundsFromPoints(pts));
    }
  }

// A helper function to decode and convert the polyline string
  List<LatLng> decodePolylineToLatLng(String polylineString) {
    // 1. Decode the string into a list of number lists (e.g., [[lat, lng], ...])
    List<List<num>> decodedPoints = decodePolyline(polylineString);

    // 2. Map each [lat, lng] pair to a LatLng object, ensuring conversion to double
    List<LatLng> latLngPoints = decodedPoints
        .map((point) => LatLng(point[0].toDouble(), point[1].toDouble()))
        .toList();

    return latLngPoints;
  }

  // =================================================================
  // 4. منطق الأداء الذكي (Smart Performance Logic)
  // =================================================================
  void _analyzePerformance() {
    final int sum = _performanceReadings.reduce((a, b) => a + b);
    final double averageTime = sum / _performanceReadings.length;
    if (averageTime > 1000) {
      // إذا كانت العملية تستغرق أكثر من ثانية
      _suggestOptimization();
    }
  }

  void _suggestOptimization() {
    Get.snackbar(
      "تحسين أداء التطبيق",
      "لضمان أفضل تجربة، نقترح تعديل الإعدادات لتناسب جهازك. هل تود المتابعة؟",
      duration: const Duration(seconds: 15),
      mainButton: TextButton(
        child: const Text("نعم، قم بالتحسين"),
        onPressed: () {
          updateInterval.value = 8; // غير الفترة إلى 8 ثوانٍ
          // save setting to shared_preferences
          box.write(BoxName.updateInterval, 8);
          Get.back();
        },
      ),
    );
  }

  // =================================================================
  // 5. دوال مساعدة (Helper Functions)
  // =================================================================
  void _resetRouteState() {
    activeRouteSteps.clear();
    traveledPathPoints.clear();
    upcomingPathPoints.clear();
    _allPointsForActiveRoute.clear();
    currentStepIndex = 0;
  }

  String _parseInstruction(String html) =>
      html.replaceAll(RegExp(r'<[^>]*>'), '');

  Future<void> _fitToBounds(LatLngBounds b, {double padding = 60}) async {
    await mapController
        ?.animateCamera(CameraUpdate.newLatLngBounds(b, padding));
  }

  double distanceBetweenDriverAndPassengerWhenConfirm = 0;
  getMap(String origin, destination) async {
    isLoading = false;

    update();

    var url =
        ('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang)}&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}');

    var response = await CRUD().getGoogleApi(link: url, payload: {});
    Log.print('response: ${response}');
    data = response['routes'][0]['legs'];
    distanceBetweenDriverAndPassengerWhenConfirm =
        (data[0]['distance']['value']) / 1000;
    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));
    }
    if (polyLines.isNotEmpty) {
      clearPolyline();
      var polyline = Polyline(
        polylineId: PolylineId(response["routes"][0]["summary"]),
        points: polylineCoordinates,
        width: 10,
        color: AppColor.blueColor,
      );
      polyLines.add(polyline);
      // rideConfirm = false;
      update();
    } else {
      var polyline = Polyline(
        polylineId: PolylineId(response["routes"][0]["summary"]),
        points: polylineCoordinates,
        width: 10,
        color: AppColor.blueColor,
      );
      // final dataBounds = response["routes"][0]["bounds"];

      // updateCameraFromBoundsAfterGetMap(dataBounds);

// Fit the camera to the bounds

      polyLines.add(polyline);
      // rideConfirm = false;
      //  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);

// Fit the camera to the bounds
      var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData!, 140);
      mapController!.animateCamera(cameraUpdate);
      update();
    }
  }

  void checkForNextStep(LatLng currentPosition) {
    if (currentStepIndex >= routeSteps.length) return;

    final step = routeSteps[currentStepIndex];
    final endLocation = step['end_location'];
    final endLatLng = LatLng(endLocation['lat'], endLocation['lng']);

    final distance = calculateDistance(
      currentPosition.latitude,
      currentPosition.longitude,
      endLatLng.latitude,
      endLatLng.longitude,
    );

    if (distance < 50) {
      // 50 متر قبل النقطة
      currentStepIndex++;
      if (currentStepIndex < routeSteps.length) {
        currentInstruction = _parseInstruction(
            routeSteps[currentStepIndex]['html_instructions']);
        Get.isRegistered<TextToSpeechController>()
            ? Get.find<TextToSpeechController>().speakText(currentInstruction)
            : Get.put(TextToSpeechController()).speakText(currentInstruction);
        Log.print('Current Instruction: $currentInstruction');
        update();
      }
    }
  }

  /// Calculates the distance in meters between two latitude/longitude points.
  double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
    const double earthRadius = 6371000; // meters
    double dLat = _degreesToRadians(lat2 - lat1);
    double dLon = _degreesToRadians(lon2 - lon1);

    double a = (sin(dLat / 2) * sin(dLat / 2)) +
        cos(_degreesToRadians(lat1)) *
            cos(_degreesToRadians(lat2)) *
            (sin(dLon / 2) * sin(dLon / 2));
    double c = 2 * atan2(sqrt(a), sqrt(1 - a));
    double distance = earthRadius * c;
    return distance;
  }

  double _degreesToRadians(double degrees) {
    return degrees * (3.1415926535897932 / 180.0);
  }

  // String _parseInstruction(String htmlInstruction) {
  //   return htmlInstruction.replaceAll(RegExp(r'<[^>]*>'), '');
  // }

  void checkDestinationProximity() {
    final distance = calculateDistance(
      myLocation.latitude,
      myLocation.longitude,
      latLngPassengerDestination.latitude,
      latLngPassengerDestination.longitude,
    );

    if (distance < 300) {
      // 300 متر قبل الوجهة
      Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
        "You are near the destination".tr,
        "You are near the destination".tr,
        tokenPassenger,
        [
          box.read(BoxName.driverID),
          rideId,
          box.read(BoxName.tokenDriver),
          paymentAmount.toString()
        ],
        'ding.wav',
      );
      // يمكن إضافة أي إجراء آخر هنا عند الاقتراب من الوجهة
    }
  }

  List<LatLngBounds> stepBounds = [];
  List<LatLng> stepEndPoints = [];
  List<String> stepInstructions = [];
  StreamSubscription<Position>? _posSub;
  DateTime _lastCameraUpdateTs = DateTime.fromMillisecondsSinceEpoch(0);

  getMapDestination(String origin, destination) async {
    var url =
        ('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang)}&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}');

    var response = await CRUD().getGoogleApi(link: url, payload: {});
    dataDestination = response['routes'][0]['legs'];
    final points =
        decodePolyline(response["routes"][0]["overview_polyline"]["points"]);

    polylineCoordinatesDestination.clear();
    for (int i = 0; i < points.length; i++) {
      double lat = points[i][0].toDouble();
      double lng = points[i][1].toDouble();
      polylineCoordinatesDestination.add(LatLng(lat, lng));
    }

    // الخطوات من أول leg
    routeSteps = List<Map<String, dynamic>>.from(dataDestination[0]['steps']);

    // حضّر بيانات كل step
    _prepareStepData(routeSteps);

    currentStepIndex = 0;
    if (stepInstructions.isNotEmpty) {
      currentInstruction = _parseInstruction(stepInstructions[0]);
      Log.print('currentInstruction: $currentInstruction');
      Get.isRegistered<TextToSpeechController>()
          ? Get.find<TextToSpeechController>().speakText(currentInstruction)
          : Get.put(TextToSpeechController()).speakText(currentInstruction);
    }

    // ارسم الـ polyline الرئيسي (مثل ما لديك)
    final summary = response["routes"][0]["summary"];
    final polyline = Polyline(
      polylineId: PolylineId(summary.isEmpty ? 'route' : summary),
      points: polylineCoordinatesDestination,
      width: 10,
      color: AppColor.redColor,
    );
    polyLinesDestination.add(polyline);

    // fit للخريطة على أول step
    if (stepBounds.isNotEmpty) {
      _fitToBounds(stepBounds[0]);
    }

    update();

    // // ابدأ التتبع الحيّ لخطوات الملاحة
    // await startListeningStepNavigation();
  }

// ————————————————————————————————————————————————————————————————
// يُنادى عند كل تحديث للموقع
  // void _onLocationTick(LatLng pos) async {
  //   if (routeSteps.isEmpty || currentStepIndex >= stepBounds.length) return;

  //   // إذا تجاوزت نهاية الـ step الحالية بمسافة صغيرة -> انتقل
  //   final double dToEnd = _distanceMeters(pos, stepEndPoints[currentStepIndex]);
  //   final bool nearEnd = dToEnd <= 25; // عتبة 25م (عدّلها حسب حاجتك)

  //   // إذا دخلت نطاق الـ step التالية -> انتقل
  //   bool insideNext = false;
  //   if (currentStepIndex < stepBounds.length - 1) {
  //     insideNext = _contains(stepBounds[currentStepIndex + 1], pos);
  //   }

  //   if (nearEnd || insideNext) {
  //     _advanceStep();
  //     return;
  //   }

  //   // تحديث الكاميرا بشكل خفيف أثناء الحركة (كل 2 ثانية مثلاً)
  //   final now = DateTime.now();
  //   if (now.difference(_lastCameraUpdateTs).inMilliseconds > 2000) {
  //     _lastCameraUpdateTs = now;
  //     // ركّز على bounds الحالية مع الحفاظ على تتبّع عام
  //     _fitToBounds(stepBounds[currentStepIndex], padding: 60);
  //   }
  // }

  LatLngBounds _boundsFromPoints(List<LatLng> pts) {
    double? minLat, maxLat, minLng, maxLng;
    for (final p in pts) {
      minLat = (minLat == null) ? p.latitude : math.min(minLat, p.latitude);
      maxLat = (maxLat == null) ? p.latitude : math.max(maxLat, p.latitude);
      minLng = (minLng == null) ? p.longitude : math.min(minLng, p.longitude);
      maxLng = (maxLng == null) ? p.longitude : math.max(maxLng, p.longitude);
    }
    return LatLngBounds(
      southwest: LatLng(minLat ?? 0, minLng ?? 0),
      northeast: LatLng(maxLat ?? 0, maxLng ?? 0),
    );
  }

  bool _contains(LatLngBounds b, LatLng p) {
    final south = math.min(b.southwest.latitude, b.northeast.latitude);
    final north = math.max(b.southwest.latitude, b.northeast.latitude);
    final west = math.min(b.southwest.longitude, b.northeast.longitude);
    final east = math.max(b.southwest.longitude, b.northeast.longitude);
    return (p.latitude >= south &&
        p.latitude <= north &&
        p.longitude >= west &&
        p.longitude <= east);
  }

  double _distanceMeters(LatLng a, LatLng b) {
    // هافرساين مبسطة
    const R = 6371000.0; // m
    final dLat = _deg2rad(b.latitude - a.latitude);
    final dLng = _deg2rad(b.longitude - a.longitude);
    final s1 = math.sin(dLat / 2);
    final s2 = math.sin(dLng / 2);
    final aa = s1 * s1 +
        math.cos(_deg2rad(a.latitude)) *
            math.cos(_deg2rad(b.latitude)) *
            s2 *
            s2;
    final c = 2 * math.atan2(math.sqrt(aa), math.sqrt(1 - aa));
    return R * c;
  }

  double _deg2rad(double d) => d * math.pi / 180.0;

// تحريك الكاميرا لباوند معيّن
  // Future<void> _fitToBounds(LatLngBounds b, {double padding = 40}) async {
  //   if (mapController == null) return;
  //   try {
  //     // أحياناً يلزم انتظار فريم حتى تكون الخريطة مرسومة
  //     await Future.delayed(const Duration(milliseconds: 50));
  //     await mapController!.animateCamera(
  //       CameraUpdate.newLatLngBounds(b, padding),
  //     );
  //   } catch (_) {
  //     // fallback لو حصلت مشكلة الحجم
  //     final center = LatLng(
  //       (b.northeast.latitude + b.southwest.latitude) / 2,
  //       (b.northeast.longitude + b.southwest.longitude) / 2,
  //     );
  //     await mapController!.animateCamera(CameraUpdate.newLatLng(center));
  //   }
  // }

// الانتقال للخطوة التالية وتحديث التعليمات والكاميرا
  // void _advanceStep() {
  //   if (currentStepIndex >= stepBounds.length - 1) return;

  //   currentStepIndex++;
  //   currentInstruction = _parseInstruction(stepInstructions[currentStepIndex]);

  //   // نطق التعليمات
  //   if (Get.isRegistered<TextToSpeechController>()) {
  //     Get.find<TextToSpeechController>().speakText(currentInstruction);
  //   } else {
  //     Get.put(TextToSpeechController()).speakText(currentInstruction);
  //   }

  //   // تركيز الكاميرا على باوند الخطوة الجديدة
  //   _fitToBounds(stepBounds[currentStepIndex]);
  //   update();
  // }

  // void _prepareStepData(List<Map<String, dynamic>> steps) {
  //   stepBounds.clear();
  //   stepEndPoints.clear();
  //   stepInstructions.clear();

  //   for (final s in steps) {
  //     // 1) instruction
  //     final html = (s['html_instructions'] ?? '').toString();
  //     stepInstructions.add(html);

  //     // 2) end point
  //     final end = s['end_location'];
  //     final endLatLng = LatLng(
  //         (end['lat'] as num).toDouble(), (end['lng'] as num).toDouble());
  //     stepEndPoints.add(endLatLng);

  //     // 3) bounds من الـ polyline (إن لم يوجد bounds جاهز من الـ API)
  //     List<LatLng> pts = [];
  //     if (s['polyline'] != null && s['polyline']['points'] != null) {
  //       final decoded = decodePolyline(s['polyline']['points']);
  //       for (var p in decoded) {
  //         pts.add(LatLng((p[0] as num).toDouble(), (p[1] as num).toDouble()));
  //       }
  //     } else {
  //       // fallback: استخدم start/end فقط
  //       final start = s['start_location'];
  //       pts.add(LatLng((start['lat'] as num).toDouble(),
  //           (start['lng'] as num).toDouble()));
  //       pts.add(endLatLng);
  //     }
  //     stepBounds.add(_boundsFromPoints(pts));
  //   }
  // }
//   getMapDestination(String origin, destination) async {
//     var url =
//         ('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang)}&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}');

//     var response = await CRUD().getGoogleApi(link: url, payload: {});
//     dataDestination = response['routes'][0]['legs'];
//     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();
//       polylineCoordinatesDestination.add(LatLng(lat, lng));
//     }
//     // استخراج الخطوات
//     routeSteps = List<Map<String, dynamic>>.from(dataDestination[0]['steps']);
//     Log.print('routeSteps: ${routeSteps}');
//     currentStepIndex = 0;
//     if (routeSteps.isNotEmpty) {
//       currentInstruction =
//           _parseInstruction(routeSteps[0]['html_instructions']);
//       Log.print('currentInstruction: ${currentInstruction}');
//       Get.isRegistered<TextToSpeechController>()
//           ? Get.find<TextToSpeechController>().speakText(currentInstruction)
//           : Get.put(TextToSpeechController()).speakText(currentInstruction);
//     }
//     update();

// // دالة مساعدة لتنظيف التعليمات

//     if (polyLinesDestination.isNotEmpty) {
//       // clearPolyline();
//       var polyline = Polyline(
//         polylineId: PolylineId(response["routes"][0]["summary"]),
//         points: polylineCoordinatesDestination,
//         width: 10,
//         color: AppColor.redColor,
//       );
//       polyLinesDestination.add(polyline);
//       // rideConfirm = false;
//       update();
//     } else {
//       var polyline = Polyline(
//         polylineId: PolylineId(response["routes"][0]["summary"]),
//         points: polylineCoordinatesDestination,
//         width: 10,
//         color: AppColor.redColor,
//       );
//       // final dataBounds = response["routes"][0]["bounds"];

//       // updateCameraFromBoundsAfterGetMap(dataBounds);
//       // polyLinesDestination.add(polyline);
//       // rideConfirm = false;
//       //  Define the northeast and southwest coordinates

//       update();
//     }
//   }

  void updateCameraFromBoundsAfterGetMap(dynamic response) {
    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
    LatLngBounds boundsData =
        LatLngBounds(northeast: northeast, southwest: southwest);

// Fit the camera to the bounds
    var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 140);
    mapController!.animateCamera(cameraUpdate);
  }

  void changePassengerInfoWindow() {
    isPassengerInfoWindow = !isPassengerInfoWindow;
    passengerInfoWindowHeight = isPassengerInfoWindow == true ? 200 : 0;
    update();
  }

  double mpg = 0;
  calculateConsumptionFuel() {
    mpg = Get.find<HomeCaptainController>().fuelPrice /
        12; //todo in register car add mpg in box
    update();
  }

  argumentLoading() async {
    passengerLocation = Get.arguments['passengerLocation'];
    passengerDestination = Get.arguments['passengerDestination'];
    duration = Get.arguments['Duration'];
    totalCost = Get.arguments['totalCost'];
    passengerId = Get.arguments['passengerId'];
    driverId = Get.arguments['driverId'];
    distance = Get.arguments['Distance'];
    passengerName = Get.arguments['name'];
    passengerEmail = Get.arguments['email'];
    totalPricePassenger = Get.arguments['totalPassenger'];
    passengerPhone = Get.arguments['phone'];
    walletChecked = Get.arguments['WalletChecked'];
    tokenPassenger = Get.arguments['tokenPassenger'];
    direction = Get.arguments['direction'];
    durationToPassenger = Get.arguments['DurationToPassenger'];
    rideId = Get.arguments['rideId'];
    durationOfRideValue = Get.arguments['durationOfRideValue'];
    paymentAmount = Get.arguments['paymentAmount'];
    paymentMethod = Get.arguments['paymentMethod'];
    isHaveSteps = Get.arguments['isHaveSteps'];
    step0 = Get.arguments['step0'];
    step1 = Get.arguments['step1'];
    step2 = Get.arguments['step2'];
    step3 = Get.arguments['step3'];
    step4 = Get.arguments['step4'];
    passengerWalletBurc = Get.arguments['passengerWalletBurc'];
    timeOfOrder = Get.arguments['timeOfOrder'];
    carType = Get.arguments['carType'];
    kazan = Get.arguments['kazan'];
    startNameLocation = Get.arguments['startNameLocation'];
    endNameLocation = Get.arguments['endNameLocation'];

// Parse to double
    latlng(passengerLocation, passengerDestination);

    String lat = Get.find<LocationController>().myLocation.latitude.toString();
    String lng = Get.find<LocationController>().myLocation.longitude.toString();
    String origin = '$lat,$lng';
    // Set the origin and destination coordinates for the Google Maps directions request.
    Future.delayed(const Duration(seconds: 1));
    getRoute(
        origin: Get.find<LocationController>().myLocation,
        destination: latLngPassengerLocation,
        routeColor: Colors.yellow // أو أي لون
        );
    // getRoute(
    //     origin: latLngPassengerLocation,
    //     destination: latLngPassengerDestination,
    //     routeColor: Colors.blue // أو أي لون
    //     );
    // getMap(origin, passengerLocation);
    // isHaveSteps == 'haveSteps'
    //     ? (
    //         await getMapDestination(step0, step1),
    //         await getMapDestination(step1, step2),
    //         step3 == '' ? await getMapDestination(step2, step3) : () {},
    //         step4 == '' ? await getMapDestination(step3, step4) : () {},
    //       )
    //     : await getMapDestination(passengerLocation, passengerDestination);
    update();
  }

  latlng(String passengerLocation, passengerDestination) {
    double latPassengerLocation =
        double.parse(passengerLocation.toString().split(',')[0]);
    double lngPassengerLocation =
        double.parse(passengerLocation.toString().split(',')[1]);
    double latPassengerDestination =
        double.parse(passengerDestination.toString().split(',')[0]);
    double lngPassengerDestination =
        double.parse(passengerDestination.toString().split(',')[1]);
    latLngPassengerLocation =
        LatLng(latPassengerLocation, lngPassengerLocation);
    latLngPassengerDestination =
        LatLng(latPassengerDestination, lngPassengerDestination);
  }

  late Duration durationToAdd;
  int hours = 0;
  int minutes = 0;
  late String carType;
  late String kazan;
  late String startNameLocation;
  late String endNameLocation;

  Future<void> runGoogleMapDirectly() async {
    if (box.read(BoxName.googlaMapApp) == true) {
      if (Platform.isAndroid) {
        Bubble().startBubbleHead(sendAppToBackground: true);
      }
      await openGoogleMapFromDriverToPassenger();
    }
  }

  @override
  void onInit() async {
    mapAPIKEY = await storage.read(key: BoxName.mapAPIKEY);
    // Get the passenger location from the arguments.
    await argumentLoading();
    Get.put(FirebaseMessagesController());
    runGoogleMapDirectly();
    addCustomCarIcon();
    addCustomPassengerIcon();
    addCustomStartIcon();
    addCustomEndIcon();
    // updateMarker();
    // updateLocation();
    startTimerToShowPassengerInfoWindowFromDriver();
    durationToAdd = Duration(seconds: int.parse(duration));
    hours = durationToAdd.inHours;
    minutes = (durationToAdd.inMinutes % 60).round();
    calculateConsumptionFuel();
    updateLocation();
    // cancelCheckRidefromPassenger();
    // checkIsDriverNearPassenger();
    super.onInit();
  }

  Timer? _navigationTimer;
  Future<void> startListeningStepNavigation() async {
    _posSub?.cancel();
    _navigationTimer?.cancel();
    Position? pos;
    _posSub = Geolocator.getPositionStream(
      locationSettings: LocationSettings(
        accuracy: LocationAccuracy.high,
        distanceFilter: 5,
        // حدّث كل ~5 متر لتقليل الاهتزاز)
      ),
    ).listen((position) {
      // خزّن آخر موقع معروف، لكن لا تعالجه فوراً
      myLocation = LatLng(position.latitude, position.longitude);
      heading = position.heading;
      update();
    });
    _navigationTimer = Timer.periodic(
        Duration(
          seconds: box.read(BoxName.updateInterval) ?? 5,
        ), (timer) {
      // تأكد أن لدينا موقع صالح قبل المعالجة
      if (myLocation.latitude != 0) {
        // استدعِ دالة المعالجة الثقيلة هنا
        onLocationUpdated(pos!);
      }
    });
    // _posSub = Geolocator.getPositionStream(
    //   locationSettings: const LocationSettings(
    //     accuracy: LocationAccuracy.high,
    //     distanceFilter: 5, // حدّث كل ~5 متر لتقليل الاهتزاز
    //   ),
    // ).listen((pos) => _onLocationTick(LatLng(pos.latitude, pos.longitude)));
  }

  void stopListeningStepNavigation() {
    _posSub?.cancel();
    _posSub = null;
  }
}
