import 'dart:async';
import 'dart:ui';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:sefer_driver/controller/home/captin/home_captain_controller.dart';
import 'package:sefer_driver/views/widgets/error_snakbar.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' as geo;
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:url_launcher/url_launcher.dart';

import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../constant/country_polygons.dart';
import '../../../constant/links.dart';
import '../../../constant/table_names.dart';
import '../../../env/env.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 '../../firebase/notification_service.dart';
import '../../functions/crud.dart';
import '../../functions/location_controller.dart';
import '../../functions/tts.dart';
import 'behavior_controller.dart';

class MapDriverController extends GetxController
    with GetSingleTickerProviderStateMixin {
  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;
  InlqBitmap carIcon = InlqBitmap.defaultMarker;
  InlqBitmap passengerIcon = InlqBitmap.defaultMarker;
  InlqBitmap startIcon = InlqBitmap.defaultMarker;
  InlqBitmap endIcon = InlqBitmap.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;
  String distance = '0';
  String? passengerName;
  late String passengerEmail;
  late String totalPricePassenger;
  late String passengerPhone;
  late String rideId;
  late String isHaveSteps;
  String paymentAmount = '0';
  late String paymentMethod;
  late String passengerId;
  late String driverId;
  late String tokenPassenger;
  String durationToPassenger = '100';
  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;

  // ─── Navigation & Smoothing ──────────────────────────────────────────
  AnimationController? _animController;
  LatLng? smoothedLocation;
  double smoothedHeading = 0.0;
  LatLng? _oldLoc;
  LatLng? _targetLoc;
  double _oldHeading = 0.0;
  double _targetHeading = 0.0;

  List<Map<String, dynamic>> routeSteps = [];
  int currentStepIndex = 0;
  String currentInstruction = "";
  String nextInstruction = "";
  String distanceToNextStep = "";
  int currentManeuverModifier = 0;
  bool _nextInstructionSpoken = false;
  bool isTtsEnabled = true;
  StreamSubscription<geo.Position>? _locationSubscription;
  // ─────────────────────────────────────────────────────────────────────
  bool isDriverNearPassengerStart = false;
  IntaleqMapController? mapController;
  late LatLng myLocation;
  int remainingTimeTimerRideBegin = 60;
  String stringRemainingTimeRideBegin = '';
  String stringRemainingTimeRideBegin1 = '';
  double progressTimerRideBegin = 0;
  Timer? timer;
  String? mapAPIKEY;
  final zones = <Zone>[];
  String canelString = 'yet';
  LatLng latLngPassengerLocation = LatLng(0, 0);
  late LatLng latLngPassengerDestination = LatLng(0, 0);



  // في MapDriverController

  void toggleTts() {
    isTtsEnabled = !isTtsEnabled;
    if (!isTtsEnabled && Get.isRegistered<TextToSpeechController>()) {
      Get.find<TextToSpeechController>().stop();
    }
    update();
  }

  void playVoiceInstruction(String text) {
    if (!isTtsEnabled) return;
    if (Get.isRegistered<TextToSpeechController>()) {
      Get.find<TextToSpeechController>().speakText(text);
    }
  }

  void disposeEverything() {
    onClose();
  }

  @override
  void onClose() {
    print("--- KILLING ALL DRIVER TIMERS ---");
    _rideTimer?.cancel();
    _rideTimer = null;
    _waitingTimer?.cancel();
    timer?.cancel();
    timer = null;

    _navigationTimer?.cancel();
    _navigationTimer = null;

    _posSub?.cancel();
    _posSub = null;

    _animController?.dispose();
    _locationSubscription?.cancel();

    super.onClose();
  }

  void onMapCreated(IntaleqMapController controller) {
    mapController = controller;
    if (Get.isRegistered<LocationController>()) {
      myLocation = Get.find<LocationController>().myLocation;
      controller.animateCamera(CameraUpdate.newLatLngZoom(myLocation, 16));
    }

    // 🔥 رسم المسار فور جاهزية الخريطة
    if (isRideStarted) {
      // إذا كانت الرحلة بدأت، ارسم للمكان النهائي
      getRoute(
          origin: myLocation,
          destination: latLngPassengerDestination,
          routeColor: Colors.blue);
    } else {
      // إذا كان السائق ذاهب للراكب
      getRoute(
          origin: myLocation,
          destination: latLngPassengerLocation,
          routeColor: Colors.yellow);
    }

    // بدء الاستماع للموقع للملاحة وتحديث الماركر
    startListeningStepNavigation();
  }

  bool isCameraLocked = true; // للتحكم في تتبع الكاميرا

  Future<void> startListeningStepNavigation() async {
    _posSub?.cancel();

    _posSub = Geolocator.getPositionStream(
      locationSettings: LocationSettings(
        accuracy: LocationAccuracy.bestForNavigation, // دقة عالية للملاحة
        distanceFilter: 5, // تحديث كل 5 أمتار
      ),
    ).listen((position) {
      LatLng newLoc = LatLng(position.latitude, position.longitude);

      // فلتر الاهتزاز البسيط (Jitter Filter)
      if (_lastRecordedLocation != null) {
        double dist = Geolocator.distanceBetween(
            newLoc.latitude,
            newLoc.longitude,
            _lastRecordedLocation!.latitude,
            _lastRecordedLocation!.longitude);
        if (dist < 2.0) return; // تجاهل الحركة الطفيفة
      }

      _lastRecordedLocation = newLoc;
      myLocation = newLoc;
      double heading = position.heading;
      double speedKmh = position.speed * 3.6;

      if (!isClosed) {
        // 1. تحديث الماركر
        updateMarker();

        // 2. تحديث المسار (Smart Snapping)
        if (upcomingPathPoints.isNotEmpty) {
          _updateTraveledPolylineSmart(myLocation);
        }

        // 3. تحريك الكاميرا (Navigation Mode)
        // فقط إذا كان "القفل" مفعلاً والسرعة > 5 كم (لتجنب الدوران العشوائي عند الوقوف)
        if (isCameraLocked && mapController != null) {
          double bearing = (speedKmh > 5) ? heading : 0.0;
          // ملاحظة: يمكنك تخزين آخر bearing معروف واستخدامه عند التوقف لتحسين التجربة
          _animateCameraToNavigationMode(newLoc, bearing);
        }

        // 4. فحص التعليمات الصوتية
        checkForNextStep(myLocation);

        // 5. فحص الوصول للوجهة (للإشعار)
        checkDestinationProximity();

        update();
      }
    });
  }

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

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

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

  @override
  void dispose() {
    print("--- KILLING ALL DRIVER TIMERS ---");
    _stopAllServices();
    super.dispose();
  }

  void _stopAllServices() {
    _rideTimer?.cancel();
    _passengerTimer?.cancel();
    _waitingTimer?.cancel();
    _posSub?.cancel();
    // mapController?.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();
  }

// متغير لمنع التكرار
  bool _isCancelReceived = false;

  /// **معالجة إلغاء الراكب الموحدة (Gatekeeper)**
  void processRideCancelledByPassenger(String reason,
      {String source = "Unknown"}) {
    if (_isCancelReceived) return; // تم المعالجة مسبقاً
    _isCancelReceived = true;

    Log.print("🚫 Ride Cancelled by Passenger via $source. Reason: $reason");

    // 1. إيقاف التوجيه والتايمرات
    // stopNavigation();
    // stopAllTimers();

    // 2. تنظيف الحالة
    box.write(BoxName.rideStatus, 'Canceled'); // أو الحالة الافتراضية
    box.remove(BoxName.rideArguments);
    box.remove(BoxName.passengerID);
    box.remove(BoxName.rideId);

    // 3. عرض رسالة للسائق
    if (Get.isDialogOpen == true) {
      navigatorKey.currentState?.pop();
    }

    Get.defaultDialog(
      title: "تم إلغاء الرحلة".tr,
      titleStyle: TextStyle(color: Colors.red),
      barrierDismissible: false,
      content: Column(
        children: [
          Icon(Icons.person_off, size: 50, color: Colors.orange),
          SizedBox(height: 10),
          Text(
            "${"Passenger cancelled the ride.".tr}\n${"Reason".tr}: $reason",
            textAlign: TextAlign.center,
          ),
        ],
      ),
      confirm: ElevatedButton(
        onPressed: () {
          navigatorKey.currentState?.pop(); // إغلاق الديالوج
          Get.offAll(() => HomeCaptain()); // العودة للرئيسية
        },
        child: Text("OK".tr),
      ),
    );

    // تشغيل صوت تنبيه للإلغاء
    // AudioService.playCancelSound();
  }

  Future<void> cancelTripFromDriverAfterApplied() async {
    if (formKeyCancel.currentState!.validate()) {
      Get.dialog(const Center(child: CircularProgressIndicator()),
          barrierDismissible: false);

      try {
        // 1. استدعاء السيرفر
        var response = await CRUD().post(
            link: "${AppLink.ride}/rides/cancel_ride_by_driver.php",
            payload: {
              "ride_id": (rideId).toString(),
              "driver_id": box.read(BoxName.driverID).toString(),
              "reason": (cancelTripCotroller.text) ?? '',
              "passenger_token": tokenPassenger.toString(),
            });

        if (response['status'] == 'success') {
          // 🔥🔥 معالجة الحظر (The Penalty Logic) 🔥🔥
          bool isBlocked = response['is_blocked'] ?? false;

          if (isBlocked) {
            String blockExpiryStr =
                response['block_until']; // "2024-10-10 14:30:00"

            // حفظ تاريخ فك الحظر في الذاكرة المحلية
            box.write(BoxName.blockUntilDate, blockExpiryStr);

            // تحويل الحالة لأوفلاين إجبارياً
            box.write(BoxName.statusDriverLocation, 'blocked');

            // عرض رسالة العقوبة
            Get.snackbar(
                "Your account is temporarily restricted ⛔".tr,
                "Due to excessive cancellations (3 times), receiving orders has been suspended for 4 hours."
                    .tr,
                duration: Duration(seconds: 8),
                backgroundColor: Colors.red,
                colorText: Colors.white,
                snackPosition: SnackPosition.BOTTOM);
          } else {
            // تحذير فقط
            int count = response['cancel_count'] ?? 0;
            Get.snackbar("تنبيه",
                "لقد ألغيت $count رحلات اليوم. الوصول لـ 3 سيعرضك للإيقاف المؤقت.",
                backgroundColor: Colors.orange);
          }

          // تنظيف البيانات
          box.remove(BoxName.rideArgumentsFromBackground);
          box.remove(BoxName.rideArguments);
          box.remove(BoxName.passengerID);
          box.remove(BoxName.rideId);
          box.write(BoxName.rideStatus, 'Cancel');

          // تسجيل محلي (اختياري)
          try {
            await sql.insertData({
              'order_id': rideId,
              'created_at': DateTime.now().toString(),
              'driver_id': box.read(BoxName.driverID),
            }, TableName.driverOrdersRefuse);
          } catch (_) {}

          if (Get.isRegistered<HomeCaptainController>()) {
            Get.find<HomeCaptainController>().getRefusedOrderByCaptain();
          } else {
            // في حال لم يكن مسجل (جاي من background)
            Get.put(HomeCaptainController()).getRefusedOrderByCaptain();
          }

          if (Get.isDialogOpen == true) {
            navigatorKey.currentState?.pop();
          }
          Get.offAll(
              () => HomeCaptain()); // العودة للرئيسية ليتم تطبيق الحظر هناك
        } else {
          if (Get.isDialogOpen == true) {
            navigatorKey.currentState?.pop();
          }
          Get.snackbar("Error", "Failed to cancel ride");
        }
      } catch (e) {
        if (Get.isDialogOpen == true) {
          navigatorKey.currentState?.pop();
        }
        Log.print("Error: $e");
      }
    }
  }

  Timer? _passengerTimer; // مرجع للتايمر لإيقافه لاحقاً
  /// **بدء مؤقت الوصول للراكب (Passenger Arrival Timer)**
  ///
  /// تقوم هذه الدالة بإدارة العد التنازلي للوقت المتوقع لوصول السائق إلى موقع الراكب.
  ///
  /// **آلية العمل:**
  /// 1. تتحقق من حالة الرحلة؛ إذا كانت قد بدأت بالفعل ('Begin')، تخفي نافذة المعلومات وتوقف العمل.
  /// 2. تحسب المدة الإجمالية من [durationToPassenger].
  /// 3. تستخدم [Timer.periodic] لتحديث الواجهة كل ثانية بدقة عالية.
  /// 4. تقوم بحساب النسبة المئوية [progressToPassenger] وتنسيق الوقت المتبقي [stringRemainingTimeToPassenger].
  /// 5. عند انتهاء الوقت، تُفعل زر بدء الرحلة [isBtnRideBegin].
  void startTimerToShowPassengerInfoWindowFromDriver() {
    // 1. تنظيف أي تايمر سابق لضمان عدم تداخل العدادات
    _passengerTimer?.cancel();

    // 2. التحقق من حالة الرحلة
    String currentStatus = box.read(BoxName.rideStatus) ?? '';
    if (currentStatus == 'Begin') {
      Log.print('rideStatus from map: $currentStatus - Hiding Info Window');
      isPassengerInfoWindow = false;
      update();
      return;
    }

    // 3. تهيئة المتغيرات
    isPassengerInfoWindow = true;
    final int totalDuration =
        int.tryParse(durationToPassenger.toString()) ?? 60;

    // استخدام DateTime لضمان دقة الوقت وعدم التأثر ببطء الجهاز
    final DateTime endTime =
        DateTime.now().add(Duration(seconds: totalDuration));

    // 4. بدء التايمر الدوري
    _passengerTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      // أمان: إيقاف التايمر إذا تم إغلاق الكنترولر
      if (isClosed) {
        timer.cancel();
        return;
      }

      final DateTime now = DateTime.now();
      final int remainingSeconds = endTime.difference(now).inSeconds;

      // أ) تحديث القيم
      if (remainingSeconds <= 0) {
        // انتهى الوقت
        remainingTimeToPassenger = 0;
        progressToPassenger = 1.0;
        stringRemainingTimeToPassenger = "00:00";
        isBtnRideBegin = true;

        timer.cancel(); // إيقاف التايمر
      } else {
        // ما زال العد مستمراً
        remainingTimeToPassenger = remainingSeconds;

        // حساب النسبة المئوية (مع منع القسمة على صفر)
        progressToPassenger =
            totalDuration > 0 ? 1 - (remainingSeconds / totalDuration) : 0.0;

        // تنسيق الوقت (دقائق:ثواني)
        final int minutes = (remainingSeconds / 60).floor();
        final int seconds = remainingSeconds % 60;
        stringRemainingTimeToPassenger =
            '$minutes:${seconds.toString().padLeft(2, '0')}';
      }

      // ب) تحديث الواجهة
      update();
    });
  }

  String stringRemainingTimeToPassenger = '';

  String stringRemainingTimeWaitingPassenger = '';
  Timer? _waitingTimer; // متغير للتحكم في تايمر الانتظار
  /// **بدء مؤقت انتظار الراكب (Waiting For Passenger Timer)**
  ///
  /// تحسب الوقت الذي ينتظره السائق عند نقطة الانطلاق.
  ///
  /// **التحسينات:**
  /// 1. استبدال الحلقة التكرارية بـ [Timer.periodic] لأداء أفضل.
  /// 2. استخدام [DateTime] لحساب الوقت المتبقي بدقة حتى لو كان التطبيق في الخلفية.
  /// 3. إدارة حالات الخروج (بدء الرحلة أو انتهاء وقت الانتظار) بشكل أنظف.
  void startTimerToShowDriverWaitPassengerDuration() {
    // 1. تنظيف أي تايمر سابق
    _waitingTimer?.cancel();

    // 2. حساب المدة الكلية بالثواني
    final int totalDurationSeconds = timeWaitingPassenger * 60;

    // 3. تحديد وقت الانتهاء المتوقع (للدقة)
    final DateTime endTime =
        DateTime.now().add(Duration(seconds: totalDurationSeconds));

    Log.print("⏳ Driver Waiting Timer Started: $totalDurationSeconds seconds");

    // 4. بدء التايمر الدوري
    _waitingTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      // أ) التحقق من إغلاق الكنترولر
      if (isClosed) {
        timer.cancel();
        return;
      }

      // ب) شرط الإيقاف الفوري: إذا بدأت الرحلة فعلياً
      if (isRideBegin) {
        remainingTimeInPassengerLocatioWait = 0;
        stringRemainingTimeWaitingPassenger = "00:00";
        timer.cancel();
        update();
        return;
      }

      // ج) حساب الوقت المتبقي بناءً على الساعة الحالية
      final DateTime now = DateTime.now();
      final int remainingSeconds = endTime.difference(now).inSeconds;

      // د) تحديث المتغيرات
      if (remainingSeconds <= 0) {
        // انتهى وقت الانتظار
        remainingTimeInPassengerLocatioWait = 0;
        progressInPassengerLocationFromDriver = 1.0;
        stringRemainingTimeWaitingPassenger = "00:00";
        isdriverWaitTimeEnd = true; // تفعيل زر الإلغاء المدفوع

        timer.cancel();
      } else {
        // ما زال الانتظار جارياً
        remainingTimeInPassengerLocatioWait = remainingSeconds;

        // حساب التقدم (من 0.0 إلى 1.0)
        // Elapsed = Total - Remaining
        final int elapsed = totalDurationSeconds - remainingSeconds;
        progressInPassengerLocationFromDriver =
            totalDurationSeconds > 0 ? (elapsed / totalDurationSeconds) : 1.0;

        // تنسيق النص
        final int minutes = (remainingSeconds / 60).floor();
        final int seconds = remainingSeconds % 60;
        stringRemainingTimeWaitingPassenger =
            '$minutes:${seconds.toString().padLeft(2, '0')}';
      }

      update();
    });
  }

  bool isSocialPressed = false;
  // نغير نوع الإرجاع إلى Future<bool>
  Future<bool> driverCallPassenger() async {
    try {
      // نضع الكود داخل try لضمان عدم توقف التطبيق عند انقطاع النت
      String scam = await getDriverScam();
      int scamCount = int.tryParse(scam) ?? 0;

      // 1. منطق الحظر
      if (scamCount > 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,
          },
        );

        // نرجع false لمنع الاتصال
        return false;
      }

      // 2. تسجيل العملية (تسجيل آمن)
      if (isSocialPressed == true && passengerId != null && rideId != null) {
        box.write(BoxName.statusDriverLocation, 'off');

        // لا نستخدم await هنا لكي لا نؤخر فتح الهاتف
        CRUD().post(
          link: AppLink.addDriverScam,
          payload: {
            'driverID': box.read(BoxName.driverID),
            'passengerID': passengerId,
            'rideID': rideId,
            'isDriverCallPassenger': 'true',
          },
        );
      }

      // نسمح بالاتصال
      return true;
    } catch (e) {
      // في حال حدث خطأ في النت أو السيرفر، هل تريد السماح له بالاتصال؟
      // الأفضل نعم، حتى لا تتعطل الخدمة بسبب خطأ تقني، ونسجل الخطأ في اللوج
      print("Error in scam check: $e");
      return true;
    }
  }

// دالة مساعدة لحماية التطبيق من كراش الخرائط
  Future<void> safeAnimateCamera(CameraUpdate cameraUpdate) async {
    if (isClosed || mapController == null) return;
    try {
      await mapController!.animateCamera(cameraUpdate);
    } catch (e) {
      Log.print("Camera error ignored");
    }
  }

  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 = (res);
    Log.print('d: ${d}');

    // 1. Check if the response status is 'failure' (API level check)
    if (d['status'] == 'failure') {
      // If the API status is failure, the message is a String (e.g., 'No ride scam record found')
      // and there's no 'count' array to read.
      return '0';
    }

    // 2. Safely access the List/Map structure for 'count'
    // This assumes a successful response looks like:
    // {'status': 'success', 'message': [{'count': '12'}]}
    var messageData = d['message'];

    // Check if messageData is actually a List before accessing index [0]
    if (messageData is List &&
        messageData.isNotEmpty &&
        messageData[0] is Map) {
      return messageData[0]['count'];
    }

    // Fallback if the successful data structure is unexpected
    return '0';

    // --- FIX END ---
  }

  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;

  /// **بدء الرحلة من طرف السائق (Start Ride)**
  ///
  /// تقوم هذه الدالة بالتحقق من المسافة بين السائق والراكب، فإذا كانت قريبة (< 400م)،
  /// ترسل طلباً للسيرفر لبدء الرحلة رسمياً.
  ///
  /// * السيرفر سيقوم بإرسال الإشعارات (Socket + FCM) للراكب تلقائياً.
  /// **بدء الرحلة (Start Ride)**
  ///
  /// التحسينات:
  /// 1. إظهار Loading لمنع تكرار الضغط.
  /// 2. استخدام التحديث الموجه (Targeted Update) لمنع وميض الشاشة.
  /// 3. معالجة فشل السيرفر (Revert Logic) لضمان عدم ضياع حالة الرحلة.
  Future<void> startRideFromDriver() async {
    // 1. إظهار مؤشر تحميل فوري (Blocking)
    Get.dialog(const Center(child: CircularProgressIndicator()),
        barrierDismissible: false);

    try {
      // 2. التحقق من المسافة (Async)
      double distanceToPassenger =
          await calculateDistanceBetweenDriverAndPassengerLocation();

      // إغلاق مؤشر التحميل لأننا حصلنا على النتيجة
      if (Get.isDialogOpen == true) {
        Get.back();
      }

      if (distanceToPassenger < 150) {
        // زدت المسافة قليلاً لمرونة أكبر (150م)

        // --- أ) تحديث الحالة المحلية (Optimistic Update) ---
        changeRideToBeginToPassenger(); // تغيير المتغيرات الداخلية
        isPassengerInfoWindow = false;
        isRideStarted = true;
        isRideFinished = false;
        remainingTimeInPassengerLocatioWait = 0;
        timeWaitingPassenger = 0;

        // الحفظ في التخزين المحلي
        box.write(BoxName.statusDriverLocation, 'on');
        box.write(BoxName.rideStatus, 'Begin');

        // بدء الخدمات (الملاحة والعداد)
        await startListeningStepNavigation();
        rideIsBeginPassengerTimer();

        // --- ب) تحديث الواجهة (Targeted Updates Only) ---
        // نحدث فقط الأجزاء التي تتغير، بدلاً من إعادة رسم الخريطة كاملة
        // update(['PassengerInfo']); // لإخفاء نافذة معلومات الراكب
        // update(['DriverEndBar']); // لإظهار شريط إنهاء الرحلة
        // update(['SosConnect']); // لتفعيل زر الطوارئ (تأكد من وضع ID للودجت)
        update();
        // --- ج) إرسال الطلب للسيرفر (Background) ---
        // لا ننتظر النتيجة لتعطيل الواجهة، لكن نعالج الخطأ إن حدث
        CRUD().post(
            link: "${AppLink.server}/ride/rides/start_ride.php",
            payload: {
              'id': rideId.toString(),
              'driver_id': box.read(BoxName.driverID).toString(),
              'status': 'Begin',
              "passengerToken": tokenPassenger.toString()
            }).then((response) {
          // هنا يمكن التحقق مما إذا كان السيرفر قد رفض الطلب (اختياري)
          if (response['status'] == 'failure') {
            // Revert logic if needed (نادر الحدوث)
            Log.print("Server failed to start ride!");
          }
        });
      } else {
        // --- حالة الرفض (بعيد جداً) ---
        showDialog(
          context: Get.context!,
          builder: (context) => AlertDialog(
            title: Text('You are far from passenger location'.tr),
            content: Text(
                'Please go closer to the passenger location (less than 150m)'
                    .tr),
            actions: [
              TextButton(
                onPressed: () => Navigator.pop(context),
                child: Text('OK'.tr),
              ),
            ],
          ),
        );
      }
    } catch (e) {
      // تنظيف اللودينج في حال حدوث خطأ غير متوقع
      if (Get.isDialogOpen == true) {
        Get.back();
      }
      Log.print("Error starting ride: $e");
      Get.snackbar("Error", "Could not start ride. Please check internet.");
    }
  }

  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: 3));

        await safeAnimateCamera(
          CameraUpdate.newCameraPosition(
            CameraPosition(
              bearing: Get.find<LocationController>().heading,
              target: myLocation,
              zoom: 17,
            ),
          ),
        );
        // });
        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;
    }
  }

  /// دالة مساعدة لحساب التكلفة (Logic Helper)
  double _calculateWaitingCost() {
    bool isEgypt = box.read(BoxName.countryCode) == 'Egypt';
    double waitingMinutes = 5.0;

    if (isEgypt) {
      // معادلة مصر: (المسافة * 0.08) + (5 دقائق * 1)
      return (distanceBetweenDriverAndPassengerWhenConfirm * 0.08) +
          (waitingMinutes * 1.0);
    } else {
      // معادلة الأردن/أخرى: (المسافة * 11) + (5 دقائق * 0.06)
      // تأكد من منطق الوحدات هنا (هل المسافة بالكيلومتر أم بالمتر؟)
      return (distanceBetweenDriverAndPassengerWhenConfirm * 11) +
          (waitingMinutes * 0.06);
    }
  }

  Future<void> addWaitingTimeCostFromPassengerToDriverWallet() async {
    // ... (فحص المسافة واللودينج كما هو) ...
    Get.dialog(const Center(child: CircularProgressIndicator()),
        barrierDismissible: false);

    try {
      // 1. حساب التكلفة
      double costOfWaiting = _calculateWaitingCost();
      double costForPassenger = costOfWaiting * -1; // بالسالب

      // 2. تحديث البيانات التشغيلية (Main Server)
      // هذا الطلب لا يحتاج توكنات مالية، فقط تحديث حالة
      await CRUD().post(
          link: "${AppLink.ride}/rides/update_ride_cancel_wait.php",
          payload: {
            'ride_id': rideId.toString(),
            'driver_id': box.read(BoxName.driverID).toString(),
          });

      // 3. توليد التوكنات (Server-Side Logic Security)
      // نحتاج توكن للسائق وتوكن للراكب
      final tokens = await Future.wait([
        generateTokenDriver(costOfWaiting.toString()),
        generateTokenPassenger(costForPassenger.toString())
      ]);

      // 4. تنفيذ العملية المالية الموحدة (Payment Server)
      var paymentResponse = await CRUD().postWallet(
          link:
              "${AppLink.paymentServer}/ride/passengerWallet/process_wait_compensation.php", // الرابط الجديد
          payload: {
            'ride_id': rideId.toString(),
            'driver_id': box.read(BoxName.driverID).toString(),
            'passenger_id': passengerId.toString(),
            'amount': costOfWaiting.toString(), // المبلغ الموجب
            'amount_passenger': costForPassenger.toString(), // المبلغ السالب
            'token_driver': tokens[0],
            'token_passenger': tokens[1],
          });

      if (paymentResponse['status'] == 'success') {
        // النجاح
        if (Get.isDialogOpen == true) Get.back();

        Get.snackbar(
          'Compensation Received'.tr,
          '${'You gained'.tr} ${costOfWaiting.toStringAsFixed(2)} ${'in your wallet'.tr}',
          backgroundColor: AppColor.deepPurpleAccent,
        );

        box.write(BoxName.statusDriverLocation, 'off');
        Get.offAll(() => HomeCaptain());
      } else {
        throw Exception("Payment Transaction Failed");
      }
    } catch (e) {
      if (Get.isDialogOpen == true) Get.back();
      Log.print("Error: $e");
      Get.snackbar("Error", "Transaction failed, please try again.");
    }
  }

  /// **التحقق من إنهاء الرحلة (Validate & Finish Ride)**
  ///
  /// تقوم هذه الدالة بحماية الرحلة من الإنهاء المبكر الخاطئ.
  ///
  /// **آلية العمل:**
  /// 1. تحسب المسافة الخطية (Displacement) التي قطعها السائق بعيداً عن نقطة الانطلاق.
  /// 2. تقارن هذه المسافة مع "عتبة دنيا" (Minimum Threshold) وهي (1/5) من إجمالي مسافة الرحلة.
  /// 3. **إذا تحقق الشرط:** تظهر نافذة تأكيد الإنهاء وتستدعي [finishRideFromDriver1].
  /// 4. **إذا فشل الشرط:** تمنع الإنهاء وتصدر تنبيهاً صوتياً ونصياً بأن المسافة المقطوعة غير كافية.
  /// **التحقق من إنهاء الرحلة (Validate & Finish Ride)**
  ///
  /// [isFromSlider]: إذا كانت القيمة true، فهذا يعني أن السائق سحب الشريط
  /// وبالتالي هو موافق ضمنياً، فلا داعي لعرض ديالوج "هل أنت متأكد؟"
  Future<void> finishRideFromDriver({bool isFromSlider = false}) async {
    // 1. تحويل مسافة الرحلة الكلية

    // 1. نقوم أولاً بتنظيف النص من أي حروف (مثل 'km' أو 'كم') ونبقي الأرقام والنقطة فقط
    String cleanDistance =
        distance.toString().replaceAll(RegExp(r'[^0-9.]'), '');

// 2. حماية إضافية: إذا كان النص فارغاً بعد التنظيف نعتبره صفر
    if (cleanDistance.isEmpty) cleanDistance = "0.0";

// 3. الآن التحويل سيتم بنجاح بدون أخطاء
    final double totalTripDistanceMeters = double.parse(cleanDistance) * 1000;
    // 2. حساب المسافة المقطوعة
    final double displacementMeters = Geolocator.distanceBetween(
      latLngPassengerLocation.latitude,
      latLngPassengerLocation.longitude,
      Get.find<LocationController>().myLocation.latitude,
      Get.find<LocationController>().myLocation.longitude,
    );

    // 3. تحديد الحد الأدنى (الخمس)
    final double minimumDistanceThreshold = totalTripDistanceMeters / 5;

    Log.print('📏 Total Distance (m): $totalTripDistanceMeters');
    Log.print('🚗 Moved Displacement (m): $displacementMeters');

    // 4. اتخاذ القرار
    if (displacementMeters > minimumDistanceThreshold) {
      // ✅ الحالة سليمة

      if (isFromSlider) {
        // إذا جاء من السلايدر، نفذ فوراً
        finishRideFromDriver1();
      } else {
        // إذا جاء من زر عادي (إن وجد)، اطلب التأكيد
        MyDialog().getDialog(
          'Are you sure to exit ride?'.tr,
          '',
          () {
            Get.back();
            finishRideFromDriver1();
          },
        );
      }
    } else {
      // ❌ الحالة مرفوضة: المسافة غير كافية
      final textToSpeechController = Get.put(TextToSpeechController());

      // إظهار رسالة خطأ حتى لو سحب السلايدر
      if (Get.isDialogOpen == true) Get.back(); // إغلاق أي ديالوج سابق

      MyDialog().getDialog(
        "You haven't moved sufficiently!".tr,
        "Please complete more distance before ending.".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'];
  }

  // ... other controller code ...

  /// **إنهاء الرحلة ومعالجة المدفوعات (Finish Ride & Process Payments)**
  ///
  /// تقوم هذه الدالة بإدارة عملية إنهاء الرحلة كاملة من جانب السائق.
  ///
  /// **آلية العمل:**
  /// 1. **تحديث الواجهة:** تخفي نافذة السعر وتعرض مؤشر تحميل لمنع التكرار.
  /// 2. **حساب التكلفة:** تحسب السعر النهائي بناءً على نوع السيارة والمسافة، مع مراعاة الحد الأدنى للأجور.
  /// 3. **تجهيز البيانات:** تحضر البيانات اللازمة لتحديث حالة الرحلة (`rides`) وتسجيل الدفع (`payments`).
  /// 4. **التنفيذ المتوازي (Parallel Execution):** تستخدم `Future.wait` لإرسال طلب التحديث وطلب الدفع في آن واحد للسيرفر لتقليل وقت الانتظار.
  /// 5. **التحقق (Validation):** تتأكد من نجاح كلا العمليتين (التحديث والدفع) قبل الانتقال.
  /// 6. **الختام:** في حال النجاح، تحذف البيانات المؤقتة وتوجه السائق لصفحة التقييم. في حال الفشل، تعيد حالة الواجهة ليتمكن السائق من المحاولة مجدداً.
  /// **إنهاء الرحلة (Finish Ride)**
  ///
  /// التحسينات:
  /// 1. التحقق من المسافة المقطوعة (Anti-Fraud).
  /// 2. استخدام Future.wait لتنفيذ الطلبات بالتوازي (سرعة مضاعفة).
  /// 3. استخدام `finally` لضمان إغلاق اللودينج دائماً.
  Future<void> finishRideFromDriver1({bool isFromSlider = false}) async {
    // 1. التحقق الأمني: هل تحرك السائق فعلاً؟
    // (هذا الكود يجب أن يكون سريعاً ولا يعطل الواجهة)
    if (!await _validateTripDistance(isFromSlider)) return;

    // 2. إظهار لودينج (Blocking) لمنع التكرار
    Get.dialog(const Center(child: CircularProgressIndicator()),
        barrierDismissible: false);

    try {
      // 3. تحديث الحالة المحلية لمنع أي تفاعلات أخرى
      isRideFinished = true;
      isRideStarted = false;
      isPriceWindow = false;
      box.write(BoxName.rideStatus, 'Finished');
      box.write(BoxName.statusDriverLocation, 'off');
      box.remove(BoxName.passengerID);
      box.remove(BoxName.rideId);

      // 4. حساب التكلفة النهائية (Logic)
      _calculateFinalTotalCost();

      // 5. تجهيز البيانات (Payloads)
      final rideUpdatePayload = {
        'rideId': rideId.toString(),
        'driver_id': box.read(BoxName.driverID).toString(),
        'status': 'Finished',
        'price': totalCost,
        'passengerId': passengerId.toString(),
        'driver_token': box.read(BoxName.tokenDriver).toString(),
        'passengerToken': tokenPassenger.toString(),
      };

      // توليد توكن الدفع أولاً
      final String paymentAuthToken =
          await generateTokenDriver(paymentAmount.toString());

      final paymentProcessingPayload = {
        'rideId': rideId.toString(),
        'driverId': box.read(BoxName.driverID).toString(),
        'passengerId': passengerId.toString(),
        'paymentAmount': paymentAmount,
        'paymentMethod': paymentMethod,
        'walletChecked': walletChecked.toString(),
        'passengerWalletBurc': passengerWalletBurc.toString(),
        'authToken': paymentAuthToken,
      };

      // 6. التنفيذ المتوازي (Parallel Execution) - الأسرع
      final results = await Future.wait([
        CRUD().post(
            link: "${AppLink.ride}/rides/finish_ride_updates.php",
            payload: rideUpdatePayload),
        CRUD().postWallet(
            link:
                "${AppLink.paymentServer}/ride/payment/process_ride_payments.php",
            payload: paymentProcessingPayload),
      ]);

      final rideRes = results[0];
      final payRes = results[1];

      // 7. التحقق من النجاح
      if (rideRes['status'] == 'success' && payRes['status'] == 'success') {
        // تنظيف البيانات
        box.remove(BoxName.rideArguments);
        box.remove(BoxName.rideArgumentsFromBackground);

        // إغلاق اللودينج
        if (Get.isDialogOpen == true) Get.back();

        // إرسال تقرير السلوك (Fire and forget)
        Get.put(DriverBehaviorController())
            .sendSummaryToServer(driverId, rideId);

        // الانتقال لصفحة التقييم
        Get.off(() => RatePassenger(), arguments: {
          'passengerId': passengerId,
          'rideId': rideId,
          'price': paymentAmount.toString(),
          'walletChecked': walletChecked.toString() ?? 'false'
        });
      } else {
        throw Exception(
            "Server Error: Ride=${rideRes['status']}, Payment=${payRes['status']}");
      }
    } catch (e) {
      // 8. معالجة الأخطاء (Revert State)
      if (Get.isDialogOpen == true) Get.back(); // إغلاق اللودينج

      Log.print("Error finishing ride: $e");
      Get.snackbar(
          "Error".tr, "Failed to finish ride. Please check internet.".tr,
          backgroundColor: Colors.red, colorText: Colors.white);

      // إعادة الحالة للسماح للمستخدم بالمحاولة مرة أخرى
      isRideFinished = false;
      isRideStarted = true;
      box.write(BoxName.rideStatus, 'Begin');
      update(); // تحديث الشريط ليعود للوضع النشط
    }
  }

  // --- دوال مساعدة (Helpers) لتنظيف الكود ---

  Future<bool> _validateTripDistance(bool isFromSlider) async {
    // منطق التحقق من المسافة المقطوعة (كما هو موجود لديك)
    String cleanDistance =
        distance.toString().replaceAll(RegExp(r'[^0-9.]'), '');
    if (cleanDistance.isEmpty) cleanDistance = "0.0";

    final double totalTripDistanceMeters = double.parse(cleanDistance) * 1000;
    final double displacementMeters = Geolocator.distanceBetween(
      latLngPassengerLocation.latitude,
      latLngPassengerLocation.longitude,
      Get.find<LocationController>().myLocation.latitude,
      Get.find<LocationController>().myLocation.longitude,
    );

    final double minimumThreshold = totalTripDistanceMeters / 5;

    if (displacementMeters > minimumThreshold || isFromSlider) {
      if (isFromSlider) return true;

      // إذا لم يكن من السلايدر، نعرض تأكيد
      bool confirmed = false;
      MyDialog().getDialog('Exit Ride?'.tr, '', () {
        confirmed = true;
        Get.back();
      });
      return confirmed;
    } else {
      // المسافة غير كافية
      Get.find<TextToSpeechController>()
          .speakText("You haven't moved sufficiently!".tr);
      MyDialog().getDialog(
          "Warning".tr, "You haven't moved sufficiently!".tr, () => Get.back());
      return false;
    }
  }

  void _calculateFinalTotalCost() {
    // منطق حساب السعر (كما هو موجود لديك)
    if (price < 172) {
      totalCost = (carType == 'Comfort' ||
              carType == 'Mishwar Vip' ||
              carType == 'Lady')
          ? '200'
          : '172';
    } else if (price < double.parse(totalPricePassenger)) {
      totalCost = totalPricePassenger;
    } else {
      totalCost = (carType == 'Comfort' ||
              carType == 'Mishwar Vip' ||
              carType == 'Lady')
          ? price.toStringAsFixed(2)
          : totalPricePassenger;
    }
    paymentAmount = totalCost;
  }

  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 مرة واحدة على الزيادة (وليس كل ثانية).

  // =========================================================
  // الدالة الرئيسية المعدلة (العداد)
  // =========================================================
  // متغيرات العداد الجديد
  Timer? _rideTimer;
  DateTime? _rideStartTime;
  DateTime? get rideStartTime => _rideStartTime; // إضافة هذا السطر
  double currentRideDistanceKm = 0.0; // لحساب المسافة
  // متغيرات المراقبة

  // ===========================================================================
  // 4. منطق العداد والتسعير (The Engine)
  // ===========================================================================

  void rideIsBeginPassengerTimer() {
    _rideTimer?.cancel();
    _rideStartTime = DateTime.now();
    currentRideDistanceKm = 0.0;

    // جلب الاعتماديات
    final loc = Get.find<LocationController>();
    final hc = Get.find<HomeCaptainController>();

    // إعداد متغيرات التسعير
    final double perKmSpeedBase = hc.speedPrice;
    final double perKmComfortRaw = hc.comfortPrice;
    final double perKmDelivery = hc.deliveryPrice;
    final double perKmVanRaw = hc.familyPrice;
    const double electricUpliftKm = 400;
    final double perKmElectricRaw = perKmComfortRaw + electricUpliftKm;

    final double perMinNature = hc.naturePrice;
    final double perMinLate = hc.latePrice;
    final double perMinHeavy = hc.heavyPrice;

    // القيم الأولية
    final double basePassengerQuote = safeParseDouble(totalCost);
    final int quotedMinutes =
        safeParseInt(duration) != 0 ? safeParseInt(duration) : 20;
    final double kazanPct = safeParseDouble(kazan) / 100.0;

    double plannedKm = safeParseDouble(distance);
    final double startKm = loc.totalDistance / 1000;
    if (plannedKm <= 0) plannedKm = (startKm > 0) ? startKm : 0.0;

    bool isAirport(String s) =>
        s.toLowerCase().contains('airport') || s.contains('مطار');
    final bool isAirportContext =
        isAirport(startNameLocation ?? '') || isAirport(endNameLocation ?? '');

    double lastKmForNoise = loc.totalDistance / 1000;
    const double jitterMeters = 0.01; // 10 متر

    _rideTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (box.read(BoxName.rideStatus) != 'Begin') {
        timer.cancel();
        return;
      }

      try {
        final now = DateTime.now();
        final int elapsedSeconds = now.difference(_rideStartTime!).inSeconds;

        // أ) حساب المسافة المقطوعة (Logic)
        double currentTotalKm = loc.totalDistance / 1000;
        double delta = currentTotalKm - lastKmForNoise;

        if (delta.abs() > jitterMeters) {
          currentRideDistanceKm += delta;
          lastKmForNoise = currentTotalKm;
        }

        // ب) حساب السعر (Brain)
        price = _calculateCurrentPrice(
          now: now,
          elapsedSeconds: elapsedSeconds,
          liveKm: currentRideDistanceKm,
          plannedKm: plannedKm,
          startKm: startKm,
          quotedMinutes: quotedMinutes,
          basePassengerQuote: basePassengerQuote,
          kazanPct: kazanPct,
          isAirportContext: isAirportContext,
          perKmSpeedBase: perKmSpeedBase,
          perKmComfortRaw: perKmComfortRaw,
          perKmDelivery: perKmDelivery,
          perKmVanRaw: perKmVanRaw,
          perKmElectricRaw: perKmElectricRaw,
          perMinNature: perMinNature,
          perMinLate: perMinLate,
          perMinHeavy: perMinHeavy,
        );

        // ج) تحديث واجهة المستخدم
        stringRemainingTimeRideBegin =
            "${currentRideDistanceKm.toStringAsFixed(2)} km";
        speed = loc.speed * 3.6;

        update(); // تحديث الشريط فقط
      } catch (e) {
        print("Timer Error: $e");
      }
    });
  }

  double _calculateCurrentPrice({
    required DateTime now,
    required int elapsedSeconds,
    required double liveKm,
    required double plannedKm,
    required double startKm,
    required int quotedMinutes,
    required double basePassengerQuote,
    required double kazanPct,
    required bool isAirportContext,
    required double perKmSpeedBase,
    required double perKmComfortRaw,
    required double perKmDelivery,
    required double perKmVanRaw,
    required double perKmElectricRaw,
    required double perMinNature,
    required double perMinLate,
    required double perMinHeavy,
  }) {
    // 🛑 1. قاعدة السعر الثابت: تجميد السعر
    if (carType == 'Speed' ||
        carType == 'Fixed Price' ||
        carType == 'Awfar Car') {
      return basePassengerQuote;
    }

    // 🟢 2. المنطق المتغير
    const double longTripPerMin = 600.0;

    const double longDistThresholdKm = 35.0;

    // نسبة التخفيض
    double reductionPct = 0.0;
    if (liveKm > 40.0 && perKmComfortRaw > 0) {
      double r40 = (1.0 - (2600.0 / (perKmComfortRaw * 1.2))).clamp(0.0, 0.35);
      reductionPct = r40;
      if (liveKm > 100.0) {
        reductionPct = (r40 + 0.07).clamp(0.0, 0.35);
      }
    }

    // سعر الكيلومتر
    double finalPerKmRate;
    switch (carType) {
      case 'Comfort':
      case 'Mishwar Vip':
      case 'Lady':
        finalPerKmRate = perKmComfortRaw * (1.0 - reductionPct);
        break;
      case 'Electric':
        finalPerKmRate = perKmElectricRaw * (1.0 - reductionPct);
        break;
      case 'Van':
        finalPerKmRate = perKmVanRaw * (1.0 - reductionPct);
        break;
      case 'Delivery':
        finalPerKmRate = perKmDelivery;
        break;
      default:
        finalPerKmRate = perKmComfortRaw * (1.0 - reductionPct);
    }

    // سعر الدقيقة
    double perMinRate;
    if (liveKm > longDistThresholdKm) {
      perMinRate = longTripPerMin;
    } else {
      final h = now.hour;
      if (isAirportContext || h >= 21 || h < 1) {
        perMinRate = perMinLate;
      } else if (h >= 14 && h <= 17) {
        perMinRate = perMinHeavy;
      } else {
        perMinRate = perMinNature;
      }
    }

    // الفروقات
    final int elapsedMinutes = (elapsedSeconds ~/ 60);
    int extraMinutes = elapsedMinutes - quotedMinutes;
    if (extraMinutes < 0) extraMinutes = 0;

    double liveCostCalculation =
        (liveKm * finalPerKmRate) + (elapsedMinutes * perMinRate);
    double totalLivePrice = liveCostCalculation * (1.0 + kazanPct);

    // القرار النهائي (الأعلى بين المتفق عليه والمحسوب)
    return (totalLivePrice > basePassengerQuote)
        ? totalLivePrice
        : basePassengerQuote;
  }

  double recentDistanceToDash = 0;
  double recentAngelToMarker = 0;
  double speed = 0;
  void updateMarker() {
    // استخدم الماركر الذي يتحرك مع الخريطة
    markers.removeWhere((m) => m.markerId.value == 'MyLocation');
    final locCtrl = Get.find<LocationController>();
    myLocation = locCtrl.myLocation;

    markers.add(
      Marker(
        markerId: MarkerId('MyLocation'),
        position: myLocation,
        icon: carIcon,
        rotation: locCtrl.heading,
        anchor: const Offset(0.5, 0.5),
        flat: true,
        zIndex: 2,
      ),
    );
    update();
  }

  void addCustomCarIcon() {
    carIcon = InlqBitmap.fromAsset('assets/images/car.png');
    update();
  }

  void addCustomStartIcon() async {
    startIcon = InlqBitmap.fromAsset('assets/images/A.png');
    update();
  }

  void addCustomEndIcon() {
    endIcon = InlqBitmap.fromAsset('assets/images/b.png');
    update();
  }

  void addCustomPassengerIcon() {
    passengerIcon = InlqBitmap.fromAsset('assets/images/picker.png');
    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>[];
  bool _rayIntersectsSegment(LatLng point, LatLng vertex1, LatLng vertex2) {
    double px = point.longitude;
    double py = point.latitude;

    double v1x = vertex1.longitude;
    double v1y = vertex1.latitude;
    double v2x = vertex2.longitude;
    double v2y = vertex2.latitude;

    // Check if the point is outside the vertical bounds of the segment
    if ((py < v1y && py < v2y) || (py > v1y && py > v2y)) {
      return false;
    }

    // Calculate the intersection of the ray and the segment
    double intersectX = v1x + (py - v1y) * (v2x - v1x) / (v2y - v1y);

    // Check if the intersection is to the right of the point
    return intersectX > px;
  }

  // Function to check if the point is inside the polygon
  bool isPointInPolygon(LatLng point, List<LatLng> polygon) {
    int intersections = 0;
    for (int i = 0; i < polygon.length; i++) {
      LatLng vertex1 = polygon[i];
      LatLng vertex2 =
          polygon[(i + 1) % polygon.length]; // Loop back to the start

      if (_rayIntersectsSegment(point, vertex1, vertex2)) {
        intersections++;
      }
    }

    // If the number of intersections is odd, the point is inside
    return intersections % 2 != 0;
  }

  String getLocationArea(double latitude, double longitude) {
    LatLng passengerPoint = LatLng(latitude, longitude);

    // 1. فحص الأردن
    if (isPointInPolygon(passengerPoint, CountryPolygons.jordanBoundary)) {
      box.write(BoxName.countryCode, 'Jordan');
      // يمكنك تعيين AppLink.endPoint هنا إذا كان منطقك الداخلي لا يزال يعتمد عليه
      // box.write(BoxName.serverChosen,
      // AppLink.IntaleqSyriaServer); // مثال: اختر سيرفر سوريا للبيانات
      return 'Jordan';
    }

    // 2. فحص سوريا
    if (isPointInPolygon(passengerPoint, CountryPolygons.syriaBoundary)) {
      box.write(BoxName.countryCode, 'Syria');
      // box.write(BoxName.serverChosen, AppLink.IntaleqSyriaServer);
      return 'Syria';
    }

    // 3. فحص مصر
    if (isPointInPolygon(passengerPoint, CountryPolygons.egyptBoundary)) {
      box.write(BoxName.countryCode, 'Egypt');
      // box.write(BoxName.serverChosen, AppLink.IntaleqAlexandriaServer);
      return 'Egypt';
    }

    // 4. الافتراضي (إذا كان خارج المناطق المخدومة)
    box.write(BoxName.countryCode, 'Jordan');
    // box.write(BoxName.serverChosen, AppLink.IntaleqSyriaServer);
    return 'Unknown Location (Defaulting to Jordan)';
  }

  /// **جلب ورسم المسار (OSRM - New Standard System)**
  ///
  /// تستخدم السيرفر الجديد: https://routesy.intaleq.xyz/route/v1/driving
  Future<void> getRoute({
    required LatLng origin,
    required LatLng destination,
    required Color routeColor,
  }) async {
    if (mapController == null) return;

    try {
      // 1. طلب المسار من السيرفر الموحد (SaaS) لضمان الدقة وتفادي الـ 401
      final saasUrl = Uri.parse(AppLink.mapSaasRoute).replace(queryParameters: {
        'fromLat': origin.latitude.toString(),
        'fromLng': origin.longitude.toString(),
        'toLat': destination.latitude.toString(),
        'toLng': destination.longitude.toString(),
        'steps': 'true', // نحتاجها للملاحة والتوجيه
        'alternatives': 'false',
      });

      final httpResponse = await http.get(saasUrl, headers: {
        'x-api-key': Env.mapSaasKey,
        'Content-Type': 'application/json',
      });

      if (httpResponse.statusCode != 200) {
        throw Exception("Routing request failed: ${httpResponse.statusCode}");
      }

      final response = jsonDecode(httpResponse.body);

      // 2. التعامل مع الـ JSON المباشر (الذي أرسله المستخدم)
      // إذا كان الـ response يحتوي على الحقول مباشرة في الجذر
      final String? encodedPoints = response['points'];

      if (encodedPoints == null) {
        mySnackeBarError("No route points found".tr);
        return;
      }

      // 🔥 فك التشفير باستخدام compute لضمان أداء ممتاز
      List<LatLng> fullRoute =
          await compute(PolylineUtils.decode, encodedPoints);

      if (fullRoute.isEmpty) {
        mySnackeBarError("Failed to process route points".tr);
        return;
      }

      // تحديث المسافة والوقت من الـ JSON الجديد
      distance = (response['distance'] ?? 0).toString();
      duration = (response['duration'] ?? 0).toString();

      // ب) تهيئة المتغيرات
      upcomingPathPoints.assignAll(fullRoute);
      traveledPathPoints.clear();
      _lastTraveledIndex = 0;

      // ج) رسم المسار الأولي
      polyLines.clear();
      polyLines.add(Polyline(
        polylineId: const PolylineId("upcoming_route"),
        points: fullRoute,
        width: 8,
        color: routeColor,
      ));

      // د) معالجة الخطوات (Instructions) للسيرفر الموحد
      final List<dynamic> instructions = response['instructions'] ?? [];
      if (instructions.isNotEmpty) {
        routeSteps = List<Map<String, dynamic>>.from(instructions.map((e) {
          int endIdx = (e['interval'] as List)[1];
          // التأكد من أن الـ index لا يتجاوز طول المسار
          if (endIdx >= fullRoute.length) endIdx = fullRoute.length - 1;

          return {
            'html_instructions': e['text'] ?? "",
            'sign': e['sign'] ?? 0,
            'end_location': {
              'lat': fullRoute[endIdx].latitude,
              'lng': fullRoute[endIdx].longitude,
            }
          };
        }));

        currentStepIndex = 0;
        currentInstruction = routeSteps[0]['html_instructions'];
        currentManeuverModifier = routeSteps[0]['sign'];
        _nextInstructionSpoken = false;

        if (Get.isRegistered<TextToSpeechController>() && isTtsEnabled) {
          Get.find<TextToSpeechController>().speakText(currentInstruction);
        }
      } else {
        routeSteps = [];
        currentInstruction = "";
        currentManeuverModifier = 0;
      }

      // هـ) تحريك الكاميرا لتشمل المسار
      if (fullRoute.isNotEmpty) {
        final bounds = _boundsFromLatLngList(fullRoute);
        safeAnimateCamera(CameraUpdate.newLatLngBounds(bounds,
            left: 80, top: 80, right: 80, bottom: 80));
      }

      update();
    } catch (e) {
      Log.print("Route Error: $e");
    }
  }


  LatLngBounds _boundsFromLatLngList(List<LatLng> list) {
    assert(list.isNotEmpty);
    double? x0, x1, y0, y1;
    for (LatLng latLng in list) {
      if (x0 == null) {
        x0 = x1 = latLng.latitude;
        y0 = y1 = latLng.longitude;
      } else {
        if (latLng.latitude > x1!) x1 = latLng.latitude;
        if (latLng.latitude < x0) x0 = latLng.latitude;
        if (latLng.longitude > y1!) y1 = latLng.longitude;
        if (latLng.longitude < y0!) y0 = latLng.longitude;
      }
    }
    return LatLngBounds(
        northeast: LatLng(x1!, y1!), southwest: LatLng(x0!, y0!));
  }


// داخل MapDriverController

  Future<void> markDriverAsArrived() async {
    // 1. إظهار لودينج فوراً لمنع التكرار وإشعار السائق
    Get.dialog(
        const Center(
            child: CircularProgressIndicator(
          color: AppColor.gold,
        )),
        barrierDismissible: false);

    try {
      double distance =
          await calculateDistanceBetweenDriverAndPassengerLocation();

      if (distance < 100) {
        // 2. طلب الـ API
        await CRUD()
            .post(link: "${AppLink.ride}/rides/arrive_ride.php", payload: {
          "ride_id": rideId,
          "driver_id": box.read(BoxName.driverID),
          "passengerToken": tokenPassenger
        });

        // 3. إغلاق اللودينج وتحديث الواجهة
        if (Get.isDialogOpen == true) Get.back();

        // منطق بدء العداد
        startTimerToShowDriverWaitPassengerDuration();
        isArrivedSend = false;

        // تحديث فقط الجزء الخاص بمعلومات الراكب
        update();

        // رسم المسار للوجهة
        getRoute(
            origin: latLngPassengerLocation,
            destination: latLngPassengerDestination,
            routeColor: Colors.blue);
      } else {
        if (Get.isDialogOpen == true) Get.back();
        mySnackeBarError("You must be closer than 100 meters to arrive".tr);
      }
    } catch (e) {
      if (Get.isDialogOpen == true) Get.back();
      mySnackeBarError("A connection error occurred".tr);
    }
  }



  // =================================================================
  // 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(
      "Improve app performance".tr,
      "To ensure the best experience, we suggest adjusting the settings to suit your device. Would you like to proceed?"
          .tr,
      duration: const Duration(seconds: 15),
      mainButton: TextButton(
        child: Text("Yes, optimize".tr),
        onPressed: () {
          updateInterval.value = 8; // غير الفترة إلى 8 ثوانٍ
          // save setting to shared_preferences
          box.write(BoxName.updateInterval, 8);
          Get.back();
        },
      ),
    );
  }

  // =================================================================
  // 5. دوال مساعدة (Helper Functions)
  // =================================================================


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

  Future<void> _fitToBounds(LatLngBounds b, {double padding = 60}) async {
    // نستخدم الدالة الآمنة التي أنشأناها
    await safeAnimateCamera(CameraUpdate.newLatLngBounds(b,
        left: padding, top: padding, right: padding, bottom: padding));
  }

  double distanceBetweenDriverAndPassengerWhenConfirm = 0;

  // فحص التعليمات الصوتية
  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 = Geolocator.distanceBetween(
      currentPosition.latitude,
      currentPosition.longitude,
      endLatLng.latitude,
      endLatLng.longitude,
    );

    if (distance < 50) {
      // 50 متر
      currentStepIndex++;
      if (currentStepIndex < routeSteps.length) {
        currentInstruction = routeSteps[currentStepIndex]['html_instructions'];
        playVoiceInstruction(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);
  }

  bool isNearDestinationNotified = false;

  // فحص الوصول للوجهة للإشعارات
  void checkDestinationProximity() {
    if (isNearDestinationNotified) return;

    double dist = Geolocator.distanceBetween(
        myLocation.latitude,
        myLocation.longitude,
        latLngPassengerDestination.latitude,
        latLngPassengerDestination.longitude);

    if (dist < 300) {
      isNearDestinationNotified = true;
      NotificationService.sendNotification(
        target: tokenPassenger.toString(),
        title: "You are near the destination".tr,
        body: "The driver is approaching.".tr,
        isTopic: false,
        tone: 'ding',
        driverList: [],
        category: "Destination Proximity",
      );
    }
  }

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

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



  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;

  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,
        left: 140, top: 140, right: 140, bottom: 140);
    safeAnimateCamera(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 {
    try {
      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'];

      // 🔥 حفظ البيانات في الذاكرة المحلية فوراً (لفصل السوكيت عن الكنترولر)
      box.write(BoxName.passengerID, passengerId.toString());
      box.write(BoxName.rideId, rideId.toString());
      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();

      // 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 // أو أي لون
          );
      update();
    } catch (e) {
      Log.print("Error parsing arguments: $e");
    }
  }

  void latlng(String passengerLocation, String 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;
  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);
    await argumentLoading();
    Get.put(FirebaseMessagesController());
    runGoogleMapDirectly();
    addCustomCarIcon();
    addCustomPassengerIcon();
    addCustomStartIcon();
    addCustomEndIcon();

    if (!Get.isRegistered<TextToSpeechController>()) {
      Get.put(TextToSpeechController(), permanent: true);
    }

    _animController = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 1000));
    _animController!.addListener(() {
      if (_oldLoc != null && _targetLoc != null) {
        final t = _animController!.value;
        final lat = lerpDouble(_oldLoc!.latitude, _targetLoc!.latitude, t)!;
        final lng = lerpDouble(_oldLoc!.longitude, _targetLoc!.longitude, t)!;
        smoothedLocation = LatLng(lat, lng);
        smoothedHeading = _lerpAngle(_oldHeading, _targetHeading, t);
        update();
      }
    });

    _startLocationListening();

    startTimerToShowPassengerInfoWindowFromDriver();
    durationToAdd = Duration(seconds: parseDurationToInt(duration));
    hours = durationToAdd.inHours;
    minutes = (durationToAdd.inMinutes % 60).round();
    calculateConsumptionFuel();
    super.onInit();
  }

  void _startLocationListening() {
    _locationSubscription?.cancel();
    _locationSubscription = geo.Geolocator.getPositionStream(
      locationSettings: const geo.LocationSettings(
        accuracy: geo.LocationAccuracy.bestForNavigation,
        distanceFilter: 2,
      ),
    ).listen((geo.Position pos) {
      _handleLocationUpdate(pos);
    });
  }

  void _handleLocationUpdate(geo.Position pos) {
    final newLoc = LatLng(pos.latitude, pos.longitude);
    _oldLoc = smoothedLocation ?? newLoc;
    _targetLoc = newLoc;

    _oldHeading = smoothedHeading;
    if (pos.speed > 0.5) {
      _targetHeading = pos.heading;
    } else {
      _targetHeading = _oldHeading;
    }

    _animController?.forward(from: 0.0);

    if (routeSteps.isNotEmpty) {
      _checkNavigationStep(newLoc);
    }
  }

  double _lerpAngle(double from, double to, double t) {
    final double diff = ((to - from + 540.0) % 360.0) - 180.0;
    return (from + diff * t + 360.0) % 360.0;
  }

  void _checkNavigationStep(LatLng pos) {
    if (routeSteps.isEmpty || currentStepIndex >= routeSteps.length) return;

    final step = routeSteps[currentStepIndex];
    final stepLoc = step['end_location'];
    if (stepLoc == null) return;

    final double stepLat = stepLoc['lat'];
    final double stepLng = stepLoc['lng'];

    final distance = geo.Geolocator.distanceBetween(
        pos.latitude, pos.longitude, stepLat, stepLng);

    distanceToNextStep = distance > 1000
        ? "${(distance / 1000).toStringAsFixed(1)} km"
        : "${distance.toStringAsFixed(0)} m";

    if (distance < 50 &&
        !_nextInstructionSpoken &&
        (currentStepIndex + 1) < routeSteps.length) {
      final nextText =
          routeSteps[currentStepIndex + 1]['html_instructions'] ?? "";
      if (isTtsEnabled) {
        Get.find<TextToSpeechController>().speakText(nextText);
      }
      _nextInstructionSpoken = true;
    }

    if (distance < 25) {
      _advanceStep();
    }
    update();
  }

  IconData get currentManeuverIcon {
    switch (currentManeuverModifier) {
      case 4: // Arrive
        return Icons.place_rounded;
      case 6: // Roundabout
        return Icons.roundabout_right_rounded;
      case 2: // Right
        return Icons.turn_right_rounded;
      case 3: // Slight Right
        return Icons.turn_slight_right_rounded;
      case -2: // Left
        return Icons.turn_left_rounded;
      case -1: // Slight Left
        return Icons.turn_slight_left_rounded;
      case 7: // Keep Right
        return Icons.turn_right_rounded;
      case -7: // Keep Left
        return Icons.turn_left_rounded;
      case 0: // Straight
        return Icons.straight_rounded;
      default:
        return Icons.straight_rounded;
    }
  }

  void _advanceStep() {
    currentStepIndex++;
    if (currentStepIndex < routeSteps.length) {
      currentInstruction =
          routeSteps[currentStepIndex]['html_instructions'] ?? "";
      currentManeuverModifier = routeSteps[currentStepIndex]['sign'] ?? 0;
      _nextInstructionSpoken = false;
    }
  }



  int parseDurationToInt(dynamic value) {
    if (value == null) return 0;
    String text = value.toString();
    // حذف كل شيء ما عدا الأرقام (الإنجليزية)
    String digits = text.replaceAll(RegExp(r'[^0-9]'), '');
    if (digits.isEmpty) return 0;
    return int.tryParse(digits) ?? 0;
  }

  Timer? _navigationTimer;
  // أضف هذا المتغير في الكلاس
  LatLng? _lastRecordedLocation;

//   Future<void> startListeningStepNavigation() async {
//     _posSub?.cancel();
//     _navigationTimer?.cancel();

//     _posSub = Geolocator.getPositionStream(
//       locationSettings: const LocationSettings(
//         accuracy: LocationAccuracy.high,
//         distanceFilter: 5, // قللناها لـ 5 أمتار لدقة أعلى
//       ),
//     ).listen((position) {
//       LatLng newLoc = LatLng(position.latitude, position.longitude);

//       // 🔥 Jitter Filter: تجاهل التحركات الطفيفة جداً (أقل من 2 متر)
//       if (_lastRecordedLocation != null) {
//         double dist = Geolocator.distanceBetween(
//             newLoc.latitude,
//             newLoc.longitude,
//             _lastRecordedLocation!.latitude,
//             _lastRecordedLocation!.longitude);
//         if (dist < 2.0) return;
//       }

//       _lastRecordedLocation = newLoc;
//       myLocation = newLoc;
//       heading = position.heading;

//       if (!isClosed) {
//         // نحدث الماركر فوراً
//         updateMarker();

//         // 🔥 تحديث المسار بذكاء (Smart Route Snapping)
//         if (upcomingPathPoints.isNotEmpty) {
//           _updateTraveledPolylineSmart(myLocation);
//         }
// // 🔥🔥 الجزء الأهم: تحريك الكاميرا لتتبع السيارة 🔥🔥
//         if (mapController != null) {
//           _animateCameraToNavigationMode(position);
//         }
//         // التحقق من الخطوة التالية
//         checkForNextStep(myLocation);

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

  void _animateCameraToNavigationMode(LatLng target, double bearing) {
    mapController?.animateCamera(
      CameraUpdate.newCameraPosition(
        CameraPosition(
          target: target,
          bearing: bearing,
          tilt: 45.0, // منظور ثلاثي الأبعاد (3D Perspective)
          zoom: 18.0, // تقريب للملاحة
        ),
      ),
    );
  }

  // متغير لتتبع آخر نقطة وصلنا لها
  int _lastTraveledIndex = 0;

  // تحديث المسار الذكي
  void _updateTraveledPolylineSmart(LatLng currentPos) {
    if (upcomingPathPoints.isEmpty) return;

    // Sliding Window: نبحث فقط في الـ 60 نقطة القادمة
    int searchWindow = 60;
    int startIndex = _lastTraveledIndex;
    int endIndex = min(startIndex + searchWindow, upcomingPathPoints.length);

    double minDistance = double.infinity;
    int closestIndex = startIndex;
    bool foundCloser = false;

    for (int i = startIndex; i < endIndex; i++) {
      final point = upcomingPathPoints[i];
      final dist = Geolocator.distanceBetween(currentPos.latitude,
          currentPos.longitude, point.latitude, point.longitude);
      if (dist < minDistance) {
        minDistance = dist;
        closestIndex = i;
        foundCloser = true;
      }
    }

    if (foundCloser && minDistance < 50 && closestIndex > _lastTraveledIndex) {
      _lastTraveledIndex = closestIndex;

      final remaining = upcomingPathPoints.sublist(_lastTraveledIndex);
      final traveled = upcomingPathPoints.sublist(0, _lastTraveledIndex + 1);

      polyLines.removeWhere((p) => p.polylineId.value == 'upcoming_route');
      polyLines.removeWhere((p) => p.polylineId.value == 'traveled_route');

      // المسار المتبقي
      polyLines.add(Polyline(
        polylineId: const PolylineId("upcoming_route"),
        points: remaining,
        width: 8,
        color: isRideStarted ? Colors.blue : Colors.yellow,
      ));

      // المسار المقطوع (رمادي)
      polyLines.add(Polyline(
        polylineId: const PolylineId('traveled_route'),
        points: traveled,
        color: Colors.grey.withValues(alpha: 0.8),
        width: 7,
        zIndex: 1,
      ));

      update();
    }
  }

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

double safeParseDouble(dynamic value, {double defaultValue = 0.0}) {
  if (value == null) return defaultValue;
  if (value is double) return value;
  if (value is int) return value.toDouble();
  return double.tryParse(value.toString()) ?? defaultValue;
}

int safeParseInt(dynamic value, {int defaultValue = 0}) {
  if (value == null) return defaultValue;
  if (value is int) return value;
  return int.tryParse(value.toString()) ?? defaultValue;
}
