import 'dart:async';
import 'dart:convert';
import 'dart:developer';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:driver/app/wallet_screen/payment_list_screen.dart';
import 'package:driver/constant/collection_name.dart';
import 'package:driver/constant/constant.dart';
import 'package:driver/constant/send_notification.dart';
import 'package:driver/constant/show_toast_dialog.dart';
import 'package:driver/models/cab_order_model.dart';
import 'package:driver/models/user_model.dart';
import 'package:driver/models/wallet_transaction_model.dart';
import 'package:driver/services/audio_player_service.dart';
import 'package:driver/themes/app_them_data.dart';
import 'package:driver/utils/fire_store_utils.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart' as flutterMap;
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:http/http.dart' as http;
import 'package:latlong2/latlong.dart' as location;

class CabHomeController extends GetxController {
  RxBool isLoading = true.obs;
  flutterMap.MapController osmMapController = flutterMap.MapController();
  RxList<flutterMap.Marker> osmMarkers = <flutterMap.Marker>[].obs;

  StreamSubscription<DocumentSnapshot<Map<String, dynamic>>>? _driverSub;
  StreamSubscription<DocumentSnapshot<Map<String, dynamic>>>? _orderDocSub;
  StreamSubscription<QuerySnapshot<Map<String, dynamic>>>? _orderQuerySub;

  @override
  void onInit() {
    getData();
    super.onInit();
  }

  @override
  void onClose() {
    _driverSub?.cancel();
    _orderDocSub?.cancel();
    _orderQuerySub?.cancel();
    super.onClose();
  }

  Future<void> getData() async {
    _subscribeDriver();
    isLoading.value = false;
  }

  Rx<CabOrderModel> currentOrder = CabOrderModel().obs;
  Rx<UserModel> driverModel = UserModel().obs;
  Rx<UserModel> ownerModel = UserModel().obs;

  Future<void> acceptOrder() async {
    try {
      await AudioPlayerService.playSound(false);
      ShowToastDialog.showLoader("Please wait".tr);

      driverModel.value.inProgressOrderID ??= [];
      driverModel.value.inProgressOrderID!.add(currentOrder.value.id);
      driverModel.value.orderCabRequestData = null;
      await FireStoreUtils.updateUser(driverModel.value);

      currentOrder.value.status = Constant.driverAccepted;
      currentOrder.value.driverId = driverModel.value.id;
      currentOrder.value.driver = driverModel.value;
      await FireStoreUtils.setCabOrder(currentOrder.value);

      ShowToastDialog.closeLoader();

      await SendNotification.sendFcmMessage(Constant.driverAcceptedNotification, currentOrder.value.author?.fcmToken ?? "", {});
    } catch (e, s) {
      ShowToastDialog.closeLoader();
      debugPrint("Error in acceptOrder: $e");
      debugPrintStack(stackTrace: s);
      ShowToastDialog.showToast("Something went wrong. Please try again.");
    }
  }

  Future<void> rejectOrder() async {
    try {
      await AudioPlayerService.playSound(false);

      // 1️⃣ Immediately update local state (UI)
      currentOrder.value.status = Constant.driverRejected;

      currentOrder.value.rejectedByDrivers ??= [];
      if (!currentOrder.value.rejectedByDrivers!.contains(driverModel.value.id)) {
        currentOrder.value.rejectedByDrivers!.add(driverModel.value.id);
      }

      // Immediately update UI so bottom sheet hides right away
      currentOrder.refresh();

      // 2️⃣ Update driver local state right away
      driverModel.value.orderCabRequestData = null;
      driverModel.value.inProgressOrderID = [];
      await FireStoreUtils.updateUser(driverModel.value);

      // 3️⃣ Close bottom sheet immediately (don’t wait for Firestore)
      if (Get.isBottomSheetOpen ?? false) {
        Get.back();
      } else if (Constant.singleOrderReceive == false) {
        Get.back();
      }

      // 4️⃣ Clear map immediately
      await clearMap();

      // 5️⃣ Update Firestore in background (no UI wait)
      unawaited(FireStoreUtils.setCabOrder(currentOrder.value));

      // 6️⃣ Reset local current order after short delay
      Future.delayed(const Duration(milliseconds: 300), () {
        currentOrder.value = CabOrderModel();
      });
    } catch (e, s) {
      print("rejectOrder() error: $e\n$s");
    }
  }

  bool get shouldShowOrderSheet {
    final status = currentOrder.value.status;
    return currentOrder.value.id != null &&
        ![Constant.driverPending, Constant.driverRejected, Constant.orderCompleted, Constant.orderCancelled].contains(status);
  }

  Future<void> clearMap() async {
    await AudioPlayerService.playSound(false);
    if (Constant.selectedMapType != 'osm') {
      markers.clear();
      polyLines.clear();
    } else {
      osmMarkers.clear();
      routePoints.clear();
    }
    update();
  }

  Future<void> onRideStatus() async {
    await AudioPlayerService.playSound(false);
    ShowToastDialog.showLoader("Please wait".tr);
    currentOrder.value.status = Constant.orderInTransit;
    await FireStoreUtils.setCabOrder(currentOrder.value);
    ShowToastDialog.closeLoader();
    Get.back();
  }

  Future<void> completeRide() async {
    try {
      ShowToastDialog.showLoader("Please wait".tr);
      await updateCabWalletAmount(currentOrder.value);

      await FireStoreUtils.getFirestOrderOrNOtCabService(currentOrder.value).then((value) async {
        if (value == true) {
          await FireStoreUtils.updateReferralAmountCabService(currentOrder.value);
        }
      });

      currentOrder.value.status = Constant.orderCompleted;
      driverModel.value.inProgressOrderID = [];
      driverModel.value.orderCabRequestData = null;
      await FireStoreUtils.setCabOrder(currentOrder.value);
      await FireStoreUtils.updateUser(driverModel.value);

      ShowToastDialog.closeLoader();
    } catch (e) {
      ShowToastDialog.closeLoader();
      log("Error in completeRide(): $e");
    }
  }

  Future<void> updateCabWalletAmount(CabOrderModel orderModel) async {
    try {
      double totalTax = 0.0;
      double discount = 0.0;
      double subTotal = 0.0;
      double adminComm = 0.0;
      double totalAmount = 0.0;

      subTotal = double.tryParse(orderModel.subTotal ?? '0.0') ?? 0.0;
      discount = double.tryParse(orderModel.discount ?? '0.0') ?? 0.0;

      if (orderModel.taxSetting != null) {
        for (var element in orderModel.taxSetting!) {
          totalTax += Constant.calculateTax(amount: subTotal.toString(), taxModel: element);
        }
      }

      if ((orderModel.adminCommission ?? '').isNotEmpty) {
        adminComm = Constant.calculateAdminCommission(
            amount: (subTotal - discount).toString(),
            adminCommissionType: orderModel.adminCommissionType.toString(),
            adminCommission: orderModel.adminCommission ?? '0');
      }
      totalAmount = (subTotal + totalTax) - discount;

      final ownerId = orderModel.driver?.ownerId;
      final userIdForWallet = (ownerId != null && ownerId.isNotEmpty) ? ownerId : FireStoreUtils.getCurrentUid();

      if (orderModel.paymentMethod.toString() != PaymentGateway.cod.name) {
        WalletTransactionModel transactionModel = WalletTransactionModel(
            id: Constant.getUuid(),
            amount: totalAmount,
            date: Timestamp.now(),
            paymentMethod: orderModel.paymentMethod ?? '',
            transactionUser: "driver",
            userId: userIdForWallet,
            isTopup: true,
            orderId: orderModel.id,
            note: "Booking amount credited",
            paymentStatus: "success");

        final setTx = await FireStoreUtils.setWalletTransaction(transactionModel);
        if (setTx == true) {
          await FireStoreUtils.updateUserWallet(amount: totalAmount.toString(), userId: userIdForWallet);
        }
      }

      WalletTransactionModel adminTx = WalletTransactionModel(
          id: Constant.getUuid(),
          amount: adminComm,
          date: Timestamp.now(),
          paymentMethod: orderModel.paymentMethod ?? '',
          transactionUser: "driver",
          userId: userIdForWallet,
          isTopup: false,
          orderId: orderModel.id,
          note: "Admin commission deducted",
          paymentStatus: "success");

      final setAdmin = await FireStoreUtils.setWalletTransaction(adminTx);
      if (setAdmin == true) {
        await FireStoreUtils.updateUserWallet(amount: "-${adminComm.toString()}", userId: userIdForWallet);
      }
    } catch (e) {
      log("Error in updateCabWalletAmount(): $e");
    }
  }

  Future<void> getCurrentOrder() async {
    try {
      await _orderDocSub?.cancel();
      await _orderQuerySub?.cancel();

      final inProgress = driverModel.value.inProgressOrderID;
      if (inProgress != null && inProgress.isNotEmpty) {
        final String id = inProgress.first.toString();
        _orderDocSub = FireStoreUtils.fireStore
            .collection(CollectionName.ridesBooking)
            .doc(id)
            .snapshots()
            .listen((docSnap) => _handleOrderDoc(docSnap, id));
        return;
      }

      final pendingRequest = driverModel.value.orderCabRequestData;
      if (pendingRequest != null) {
        final id = pendingRequest.id?.toString();
        if (id != null && id.isNotEmpty) {
          _orderDocSub = FireStoreUtils.fireStore
              .collection(CollectionName.ridesBooking)
              .doc(id)
              .snapshots()
              .listen((docSnap) => _handleOrderDoc(docSnap, id));
          return;
        }
      }

      currentOrder.value = CabOrderModel();
      await clearMap();
      await AudioPlayerService.playSound(false);
      update();
    } catch (e) {
      log("getCurrentOrder() error: $e");
    }
  }

  Future<void> _handleOrderDoc(DocumentSnapshot<Map<String, dynamic>> docSnap, String id) async {
    try {
      if (docSnap.exists) {
        final data = docSnap.data();
        if (data != null) {
          currentOrder.value = CabOrderModel.fromJson(data);
          await changeData();
          if (currentOrder.value.status == Constant.orderCompleted) {
            driverModel.value.inProgressOrderID = [];
            await FireStoreUtils.updateUser(driverModel.value);
            currentOrder.value = CabOrderModel();
            await clearMap();
            await AudioPlayerService.playSound(false);
            update();
            return;
          } else if (currentOrder.value.status == Constant.orderRejected || currentOrder.value.status == Constant.orderCancelled) {
            driverModel.value.inProgressOrderID = [];
            driverModel.value.orderCabRequestData = null;
            await FireStoreUtils.updateUser(driverModel.value);
            currentOrder.value = CabOrderModel();
            await clearMap();
            await AudioPlayerService.playSound(false);
            update();
            return;
          }
          update();
          return;
        }
      }
      _orderQuerySub = FireStoreUtils.fireStore
          .collection(CollectionName.ridesBooking)
          .where('id', isEqualTo: id)
          .limit(1)
          .snapshots()
          .listen((qSnap) => _handleOrderQuery(qSnap));
    } catch (e) {
      log("Error listening to order doc: $e");
    }
  }

  Future<void> _handleOrderQuery(QuerySnapshot<Map<String, dynamic>> qSnap) async {
    try {
      if (qSnap.docs.isNotEmpty) {
        final doc = qSnap.docs.first;
        final data = doc.data();
        currentOrder.value = CabOrderModel.fromJson(data);
        await changeData();
        if (currentOrder.value.status == Constant.orderCompleted) {
          driverModel.value.inProgressOrderID = [];
          await FireStoreUtils.updateUser(driverModel.value);
          currentOrder.value = CabOrderModel();
          await clearMap();
          await AudioPlayerService.playSound(false);
          update();
          return;
        }
        update();
        return;
      } else {
        currentOrder.value = CabOrderModel();
        await AudioPlayerService.playSound(false);
        update();
      }
    } catch (e) {
      log("Error parsing order from query fallback: $e");
    }
  }

  RxBool isChange = false.obs;

  Future<void> changeData() async {
    if (Constant.mapType == "inappmap") {
      if (Constant.selectedMapType == "osm") {
        await getOSMPolyline();
      } else {
        await getGooglePolyline();
      }
    }
    if (currentOrder.value.status == Constant.driverPending) {
      await AudioPlayerService.playSound(true);
    } else {
      await AudioPlayerService.playSound(false);
    }
  }

  Future<void> _subscribeDriver() async {
    _driverSub = FireStoreUtils.fireStore
        .collection(CollectionName.users)
        .doc(FireStoreUtils.getCurrentUid())
        .snapshots()
        .listen((event) => _onDriverSnapshot(event));

    if (Constant.userModel!.ownerId != null && Constant.userModel!.ownerId!.isNotEmpty) {
      FireStoreUtils.fireStore.collection(CollectionName.users).doc(Constant.userModel!.ownerId).snapshots().listen(
        (event) async {
          if (event.exists) {
            ownerModel.value = UserModel.fromJson(event.data()!);
          }
        },
      );
    }
  }

  Future<void> _onDriverSnapshot(DocumentSnapshot<Map<String, dynamic>> event) async {
    try {
      if (event.exists && event.data() != null) {
        driverModel.value = UserModel.fromJson(event.data()!);
        _updateCurrentLocationMarkers();
        if (driverModel.value.id != null) {
          await getCurrentOrder();
          await changeData();
          if (driverModel.value.sectionId != null && driverModel.value.sectionId!.isNotEmpty) {
            await FireStoreUtils.getSectionBySectionId(driverModel.value.sectionId!).then((sectionValue) {
              if (sectionValue != null) {
                Constant.sectionModel = sectionValue;
              }
            });
          }
          update();
        }
      }
    } catch (e) {
      log("getDriver() listener error: $e");
    }
  }

  void _updateCurrentLocationMarkers() async {
    try {
      final loc = driverModel.value.location;
      final latLng = _safeLatLngFromLocation(loc);

      // Update reactive current location
      current.value = location.LatLng(latLng.latitude, latLng.longitude);

      // --- OSM Section ---
      try {
        setOsmMapMarker();

        if (latLng.latitude != 0.0 || latLng.longitude != 0.0) {
          osmMapController.move(location.LatLng(latLng.latitude, latLng.longitude), 16);
        }
      } catch (e) {
        log("OSM map move ignored (controller not ready): $e");
      }

      // --- GOOGLE MAP Section ---
      try {
        final driverIcon = await _bitmapDescriptorFromUrl(
          Constant.sectionModel?.markerIcon ?? '',
          width: 120,
        );

        // Remove old driver marker
        markers.remove("Driver");

        // Create new Google Marker
        markers["Driver"] = Marker(
          markerId: const MarkerId("Driver"),
          infoWindow: const InfoWindow(title: "Driver"),
          position: LatLng(current.value.latitude, current.value.longitude),
          icon: driverIcon,
          rotation: _safeRotation(),
          anchor: const Offset(0.5, 0.5),
          flat: true,
        );

        // Animate camera to current driver location
        if (mapController != null && !(current.value.latitude == 0.0 && current.value.longitude == 0.0)) {
          mapController!.animateCamera(
            CameraUpdate.newCameraPosition(
              CameraPosition(
                target: LatLng(current.value.latitude, current.value.longitude),
                zoom: 16,
                bearing: _safeRotation(),
              ),
            ),
          );
        }
      } catch (e) {
        log("Google map update ignored (controller not ready): $e");
      }

      update();

      log('_updateCurrentLocationMarkers: lat=${latLng.latitude}, lng=${latLng.longitude}, '
          'osmMarkers=${osmMarkers.length}, googleMarkers=${markers.length}');
    } catch (e) {
      log("_updateCurrentLocationMarkers error: $e");
    }
  }

  GoogleMapController? mapController;

  Rx<PolylinePoints> polylinePoints = PolylinePoints(apiKey: Constant.mapAPIKey).obs;
  RxMap<PolylineId, Polyline> polyLines = <PolylineId, Polyline>{}.obs;
  RxMap<String, Marker> markers = <String, Marker>{}.obs;

  // BitmapDescriptor? departureIcon;
  // BitmapDescriptor? destinationIcon;
  // BitmapDescriptor? taxiIcon;

  // Future<void> setIcons() async {
  //   try {
  //     if (Constant.selectedMapType == 'google') {
  //       final Uint8List departure = await Constant().getBytesFromAsset('assets/images/location_black3x.png', 100);
  //       final Uint8List destination = await Constant().getBytesFromAsset('assets/images/location_orange3x.png', 100);
  //       final Uint8List driver = Constant.sectionModel!.markerIcon == null || Constant.sectionModel!.markerIcon!.isEmpty
  //           ? await Constant().getBytesFromAsset('assets/images/ic_cab.png', 50)
  //           : await Constant().getBytesFromUrl(Constant.sectionModel!.markerIcon.toString(), width: 120);
  //
  //       departureIcon = BitmapDescriptor.fromBytes(departure);
  //       destinationIcon = BitmapDescriptor.fromBytes(destination);
  //       taxiIcon = BitmapDescriptor.fromBytes(driver);
  //     }
  //   } catch (e) {
  //     log("setIcons error: $e");
  //   }
  // }

  LatLng _safeLatLngFromLocation(dynamic loc) {
    final lat = (loc?.latitude is num) ? loc.latitude.toDouble() : 0.0;
    final lng = (loc?.longitude is num) ? loc.longitude.toDouble() : 0.0;
    return LatLng(lat, lng);
  }

  double _safeRotation() {
    return double.tryParse(driverModel.value.rotation.toString()) ?? 0.0;
  }

  Future<void> getGooglePolyline() async {
    try {
      if (currentOrder.value.id == null) return;

      final driverLatLng = _safeLatLngFromLocation(driverModel.value.location);
      List<LatLng> polylineCoordinates = [];

      // Check order status
      if (currentOrder.value.status != Constant.driverPending) {
        // Case 1: Driver Accepted or Order Shipped → Driver → Pickup
        if (currentOrder.value.status == Constant.driverAccepted || currentOrder.value.status == Constant.orderShipped) {
          final sourceLatLng = _safeLatLngFromLocation(currentOrder.value.sourceLocation);

          await _drawGoogleRoute(
            origin: driverLatLng,
            destination: sourceLatLng,
            addDriver: true,
            addSource: true,
            addDestination: false,
          );

          animateToSource();
        }

        // Case 2: Order In Transit → Driver → Destination
        else if (currentOrder.value.status == Constant.orderInTransit) {
          final destLatLng = _safeLatLngFromLocation(currentOrder.value.destinationLocation);

          await _drawGoogleRoute(
            origin: driverLatLng,
            destination: destLatLng,
            addDriver: true,
            addSource: false,
            addDestination: true,
          );

          animateToSource();
        }
      }

      // Case 3: Before driver assigned → Source → Destination
      else {
        final sourceLatLng = _safeLatLngFromLocation(currentOrder.value.sourceLocation);
        final destLatLng = _safeLatLngFromLocation(currentOrder.value.destinationLocation);

        await _drawGoogleRoute(
          origin: sourceLatLng,
          destination: destLatLng,
          addDriver: false,
          addSource: true,
          addDestination: true,
        );

        animateToSource();
      }
    } catch (e, s) {
      log('getGooglePolyline() error: $e');
      debugPrintStack(stackTrace: s);
    }
  }

  Future<void> _drawGoogleRoute({
    required LatLng origin,
    required LatLng destination,
    bool addDriver = true,
    bool addSource = true,
    bool addDestination = true,
  }) async {
    try {
      if ((origin.latitude == 0.0 && origin.longitude == 0.0) || (destination.latitude == 0.0 && destination.longitude == 0.0)) return;

      // Get route points from Google Directions API
      final result = await polylinePoints.value.getRouteBetweenCoordinates(
        request: PolylineRequest(
          origin: PointLatLng(origin.latitude, origin.longitude),
          destination: PointLatLng(destination.latitude, destination.longitude),
          mode: TravelMode.driving,
        ),
      );

      if (result.points.isEmpty) {
        log('Google route not found');
        return;
      }

      final List<LatLng> polylineCoordinates = result.points.map((p) => LatLng(p.latitude, p.longitude)).toList();

      // Draw polyline
      addPolyLine(polylineCoordinates);

      // --- Update markers (same style as OSM) ---
      await _updateGoogleMarkers(
        driverLatLng: addDriver ? origin : null,
        sourceLatLng: addSource ? _safeLatLngFromLocation(currentOrder.value.sourceLocation) : null,
        destinationLatLng: addDestination ? _safeLatLngFromLocation(currentOrder.value.destinationLocation) : null,
      );
    } catch (e) {
      log('_drawGoogleRoute error: $e');
    }
  }

  Future<void> _updateGoogleMarkers({
    LatLng? driverLatLng,
    LatLng? sourceLatLng,
    LatLng? destinationLatLng,
  }) async {
    final Map<String, Marker> newMarkers = {};

    // Driver Marker (Network Icon)
    if (driverLatLng != null) {
      final driverIcon = await _bitmapDescriptorFromUrl(
        Constant.sectionModel?.markerIcon ?? '',
        width: 120,
      );
      newMarkers['Driver'] = Marker(
        markerId: const MarkerId('Driver'),
        position: driverLatLng,
        rotation: _safeRotation(),
        anchor: const Offset(0.5, 0.5),
        flat: true,
        icon: driverIcon,
      );
    }

    // Source Marker
    if (sourceLatLng != null) {
      final srcIcon = await _bitmapDescriptorFromAsset(
        'assets/images/location_black3x.png',
        width: 100,
      );
      newMarkers['Source'] = Marker(
        markerId: const MarkerId('Source'),
        position: sourceLatLng,
        icon: srcIcon,
      );
    }

    // Destination Marker
    if (destinationLatLng != null) {
      final dstIcon = await _bitmapDescriptorFromAsset(
        'assets/images/location_orange3x.png',
        width: 100,
      );
      newMarkers['Destination'] = Marker(
        markerId: const MarkerId('Destination'),
        position: destinationLatLng,
        icon: dstIcon,
      );
    }

    // Apply all markers
    // ✅ Apply all markers to your RxMap<String, Marker>
    markers
      ..clear()
      ..addAll(newMarkers);

    update();
  }

  Future<BitmapDescriptor> _bitmapDescriptorFromUrl(String url, {int width = 100}) async {
    try {
      final Uint8List bytes = await Constant().getBytesFromUrl(url, width: width);
      return BitmapDescriptor.fromBytes(bytes);
    } catch (e) {
      log('Error loading network icon: $e');
      return BitmapDescriptor.defaultMarker;
    }
  }

  Future<BitmapDescriptor> _bitmapDescriptorFromAsset(String asset, {int width = 100}) async {
    try {
      final Uint8List bytes = await Constant().getBytesFromAsset(asset, width);
      return BitmapDescriptor.fromBytes(bytes);
    } catch (e) {
      log('Error loading asset icon: $e');
      return BitmapDescriptor.defaultMarker;
    }
  }

  void addPolyLine(List<LatLng> polylineCoordinates) {
    if (polylineCoordinates.isEmpty) {
      // nothing to draw, but ensure markers updated
      update();
      return;
    }

    PolylineId id = const PolylineId("poly");
    Polyline polyline = Polyline(
      polylineId: id,
      color: AppThemeData.primary300,
      points: polylineCoordinates,
      width: 8,
      geodesic: true,
    );
    polyLines[id] = polyline;
    update();
    updateCameraLocation(polylineCoordinates.first);
  }

  Future<void> updateCameraLocation([LatLng? source]) async {
    try {
      if (mapController == null || source == null) return;
      await mapController!.animateCamera(
        CameraUpdate.newCameraPosition(
          CameraPosition(
            target: source,
            zoom: currentOrder.value.id == null || currentOrder.value.status == Constant.driverPending ? 16 : 20,
            bearing: _safeRotation(),
          ),
        ),
      );
    } catch (e) {
      log("updateCameraLocation error: $e");
    }
  }

  void animateToSource() {
    double lat = 0.0;
    double lng = 0.0;
    final loc = driverModel.value.location;
    if (loc != null) {
      // Use string parsing to avoid nullable-toDouble issues and handle numbers/strings.
      lat = double.tryParse('${loc.latitude}') ?? 0.0;
      lng = double.tryParse('${loc.longitude}') ?? 0.0;
    }
    _updateCurrentLocationMarkers();
    osmMapController.move(location.LatLng(lat, lng), 16);
  }

  Rx<location.LatLng> source = location.LatLng(21.1702, 72.8311).obs; // Start (e.g., Surat)
  Rx<location.LatLng> current = location.LatLng(21.1800, 72.8400).obs; // Moving marker
  Rx<location.LatLng> destination = location.LatLng(21.2000, 72.8600).obs; // Destination

  void setOsmMapMarker() {
    final List<flutterMap.Marker> mk = [];

    // Add driver/current marker only when we have a valid location
    if (!(current.value.latitude == 0.0 && current.value.longitude == 0.0)) {
      mk.add(flutterMap.Marker(
        point: current.value,
        width: 45,
        height: 45,
        rotate: true,
        child: CachedNetworkImage(
          width: 50,
          height: 50,
          imageUrl: Constant.sectionModel!.markerIcon.toString(),
          placeholder: (context, url) => Constant.loader(),
          errorWidget: (context, url, error) => SizedBox(
            width: 30,
            height: 30,
            child: CircularProgressIndicator(strokeWidth: 2),
          ),
        ),
      ));
    }

    // Add source marker if we have a valid source location (or an active order with non-zero coords)
    final hasSource = currentOrder.value.sourceLocation != null &&
        !(currentOrder.value.sourceLocation?.latitude == null || currentOrder.value.sourceLocation?.longitude == null) &&
        !(currentOrder.value.sourceLocation?.latitude == 0.0 && currentOrder.value.sourceLocation?.longitude == 0.0);
    if (hasSource) {
      source.value =
          location.LatLng(currentOrder.value.sourceLocation!.latitude ?? 0.0, currentOrder.value.sourceLocation!.longitude ?? 0.0);
      mk.add(flutterMap.Marker(
        point: source.value,
        width: 40,
        height: 40,
        child: Image.asset('assets/images/location_black3x.png'),
      ));
    }

    // Add destination marker if valid
    final hasDest = currentOrder.value.destinationLocation != null &&
        !(currentOrder.value.destinationLocation?.latitude == null || currentOrder.value.destinationLocation?.longitude == null) &&
        !(currentOrder.value.destinationLocation?.latitude == 0.0 && currentOrder.value.destinationLocation?.longitude == 0.0);
    if (hasDest) {
      destination.value = location.LatLng(
          currentOrder.value.destinationLocation!.latitude ?? 0.0, currentOrder.value.destinationLocation!.longitude ?? 0.0);
      mk.add(flutterMap.Marker(
        point: destination.value,
        width: 40,
        height: 40,
        child: Image.asset('assets/images/location_orange3x.png'),
      ));
    }

    osmMarkers.value = mk;
  }

  Future<void> getOSMPolyline() async {
    try {
      if (currentOrder.value.id == null) return;

      if (currentOrder.value.status != Constant.driverPending) {
        if (currentOrder.value.status == Constant.driverAccepted || currentOrder.value.status == Constant.orderShipped) {
          final lat = (driverModel.value.location?.latitude as num?)?.toDouble() ?? 0.0;
          final lng = (driverModel.value.location?.longitude as num?)?.toDouble() ?? 0.0;
          current.value = location.LatLng(lat, lng);
          source.value = location.LatLng(
            currentOrder.value.sourceLocation?.latitude ?? 0.0,
            currentOrder.value.sourceLocation?.longitude ?? 0.0,
          );
          animateToSource();
          await fetchRoute(current.value, source.value);
          setOsmMapMarker();
        } else if (currentOrder.value.status == Constant.orderInTransit) {
          final lat = (driverModel.value.location?.latitude as num?)?.toDouble() ?? 0.0;
          final lng = (driverModel.value.location?.longitude as num?)?.toDouble() ?? 0.0;
          current.value = location.LatLng(lat, lng);
          destination.value = location.LatLng(
            currentOrder.value.destinationLocation?.latitude ?? 0.0,
            currentOrder.value.destinationLocation?.longitude ?? 0.0,
          );
          await fetchRoute(current.value, destination.value);
          setOsmMapMarker();
          animateToSource();
        }
      } else {
        current.value =
            location.LatLng(currentOrder.value.sourceLocation?.latitude ?? 0.0, currentOrder.value.sourceLocation?.longitude ?? 0.0);
        destination.value = location.LatLng(
            currentOrder.value.destinationLocation?.latitude ?? 0.0, currentOrder.value.destinationLocation?.longitude ?? 0.0);
        await fetchRoute(current.value, destination.value);
        setOsmMapMarker();
        animateToSource();
      }
    } catch (e) {
      log('getOSMPolyline error: $e');
    }
  }

  RxList<location.LatLng> routePoints = <location.LatLng>[].obs;

  Future<void> fetchRoute(location.LatLng source, location.LatLng destination) async {
    try {
      // ensure valid coords
      final bothZero = source.latitude == 0.0 && source.longitude == 0.0 && destination.latitude == 0.0 && destination.longitude == 0.0;
      if (bothZero) {
        routePoints.clear();
        return;
      }

      final url = Uri.parse(
        'https://router.project-osrm.org/route/v1/driving/${source.longitude},${source.latitude};${destination.longitude},${destination.latitude}?overview=full&geometries=geojson',
      );

      final response = await http.get(url);

      if (response.statusCode == 200) {
        final decoded = json.decode(response.body);
        if (decoded != null &&
            decoded['routes'] != null &&
            decoded['routes'] is List &&
            (decoded['routes'] as List).isNotEmpty &&
            decoded['routes'][0]['geometry'] != null) {
          final geometry = decoded['routes'][0]['geometry']['coordinates'];
          routePoints.clear();
          for (var coord in geometry) {
            if (coord is List && coord.length >= 2) {
              final lon = coord[0];
              final lat = coord[1];
              if (lat is num && lon is num) {
                routePoints.add(location.LatLng(lat.toDouble(), lon.toDouble()));
              }
            }
          }
          return;
        }
        routePoints.clear();
      } else {
        log("Failed to get route: ${response.statusCode} ${response.body}");
        routePoints.clear();
      }
    } catch (e) {
      log("fetchRoute error: $e");
      routePoints.clear();
    }
  }
}
