import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math' show cos, pi, max, min, atan2, sin, sqrt;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:location/location.dart';
import 'package:http/http.dart' as http;

import '../../../constant/box_name.dart';
import '../../../constant/links.dart';
import '../../../constant/colors.dart';
import '../../../constant/style.dart';
import '../../../constant/table_names.dart';
import '../../../main.dart'; // contains global 'box', 'sql'
import '../../../print.dart';
import '../../../services/offline_map_service.dart';
import '../../functions/crud.dart';
import '../points_for_rider_controller.dart';
import '../../../views/home/map_widget.dart/form_serch_multiy_point.dart';
import '../../../views/widgets/error_snakbar.dart';
import 'map_engine_controller.dart';
import '../deep_link_controller.dart';
import 'ride_lifecycle_controller.dart';
import 'ride_state.dart';
import '../../../constant/country_polygons.dart';
import '../../../constant/univeries_polygon.dart';

class LocationSearchController extends GetxController {
  List<Map<String, dynamic>> waypoints = [];
  String passengerLocationStringUnvirsity = 'Not in University';
  bool isInUniversity = false;
  List<String> coordinatesWithoutEmpty = [];
  LatLng? latestPosition;

  List<LatLng> polylineCoordinates0 = [];
  List<LatLng> polylineCoordinates1 = [];
  List<LatLng> polylineCoordinates2 = [];
  List<LatLng> polylineCoordinates3 = [];
  List<LatLng> polylineCoordinates4 = [];
  late List<List<LatLng>> polylineCoordinatesPointsAll = [
    polylineCoordinates0,
    polylineCoordinates1,
    polylineCoordinates2,
    polylineCoordinates3,
    polylineCoordinates4,
  ];

  bool isLoading = true;
  TextEditingController placeDestinationController = TextEditingController();
  TextEditingController placeStartController = TextEditingController();
  TextEditingController wayPoint0Controller = TextEditingController();
  TextEditingController wayPoint1Controller = TextEditingController();
  TextEditingController wayPoint2Controller = TextEditingController();
  TextEditingController wayPoint3Controller = TextEditingController();
  TextEditingController wayPoint4Controller = TextEditingController();
  TextEditingController whatsAppLocationText = TextEditingController();
  final sosFormKey = GlobalKey<FormState>();

  List<LatLng> bounds = [];
  List placesStart = [];
  List<TextEditingController> allTextEditingPlaces = [];
  List placesDestination = [];
  List wayPoint0 = [];
  List wayPoint1 = [];
  List wayPoint2 = [];
  List wayPoint3 = [];
  List wayPoint4 = [];
  List<List<dynamic>> placeListResponseAll = [];

  List<Widget> placeListResponse = [];

  PermissionStatus? permissionGranted;
  final location = Location();
  double speed = 0;

  late LatLng passengerLocation = const LatLng(32, 34);
  late LatLng newMyLocation = const LatLng(32.115295, 36.064773);
  late LatLng newStartPointLocation = const LatLng(32.115295, 36.064773);
  late LatLng newPointLocation0 = const LatLng(32.115295, 36.064773);
  late LatLng newPointLocation1 = const LatLng(32.115295, 36.064773);
  late LatLng newPointLocation2 = const LatLng(32.115295, 36.064773);
  late LatLng newPointLocation3 = const LatLng(32.115295, 36.064773);
  late LatLng newPointLocation4 = const LatLng(32.115295, 36.064773);
  late LatLng myDestination = const LatLng(32, 34);

  bool startLocationFromMap = false;
  bool passengerStartLocationFromMap = false;
  bool workLocationFromMap = false;
  bool homeLocationFromMap = false;
  bool isPassengerRideLocationWidget = false;
  bool startLocationFromMap0 = false;
  bool startLocationFromMap1 = false;
  bool startLocationFromMap2 = false;
  bool startLocationFromMap3 = false;
  bool startLocationFromMap4 = false;
  List startLocationFromMapAll = [];

  bool currentLocationToFormPlaces = false;
  bool currentLocationToFormPlaces0 = false;
  bool currentLocationToFormPlaces1 = false;
  bool currentLocationToFormPlaces2 = false;
  bool currentLocationToFormPlaces3 = false;
  bool currentLocationToFormPlaces4 = false;
  List currentLocationToFormPlacesAll = [];

  // Multi-Waypoint (max 2 stops)
  List<LatLng?> menuWaypoints = [null, null];
  List<String> menuWaypointNames = ['', ''];
  int activeMenuWaypointCount = 0;
  bool isPickingWaypoint = false;
  int pickingWaypointIndex = -1;

  int wayPointIndex = 0;
  String hintTextStartPoint = 'Search for your Start point'.tr;
  String hintTextwayPoint0 = 'Search for waypoint'.tr;
  String hintTextwayPoint1 = 'Search for waypoint'.tr;
  String hintTextwayPoint2 = 'Search for waypoint'.tr;
  String hintTextwayPoint3 = 'Search for waypoint'.tr;
  String hintTextwayPoint4 = 'Search for waypoint'.tr;
  String currentLocationString = 'Current Location'.tr;
  String currentLocationString0 = 'Current Location'.tr;
  String currentLocationString1 = 'Add Location 1'.tr;
  String currentLocationString2 = 'Add Location 2'.tr;
  String currentLocationString3 = 'Add Location 3'.tr;
  String currentLocationString4 = 'Add Location 4'.tr;
  String placesCoordinate0 = ''.tr;
  String placesCoordinate1 = ''.tr;
  String placesCoordinate2 = ''.tr;
  String placesCoordinate3 = ''.tr;
  String placesCoordinate4 = ''.tr;
  List<String> currentLocationStringAll = [];
  List<String> hintTextwayPointStringAll = [];
  var placesCoordinate = <String>[];
  String hintTextDestinationPoint = 'Select your destination'.tr;

  late String startNameAddress = '';
  late String endNameAddress = '';
  List<Map<String, dynamic>> stopPoints = [];

  double latitudeWhatsApp = 0;
  double longitudeWhatsApp = 0;
  late List recentPlaces = [];

  Timer? _camThrottle;

  final DeepLinkController _deepLinkController =
      Get.isRegistered<DeepLinkController>()
          ? Get.find<DeepLinkController>()
          : Get.put(DeepLinkController());

  @override
  void onInit() {
    super.onInit();
    placeListResponse = [
      formSearchPlaces(0),
      formSearchPlaces(1),
      formSearchPlaces(2),
      formSearchPlaces(3),
    ];
    readyWayPoints();
    getLocation();
  }

  void readyWayPoints() {
    hintTextwayPointStringAll = [
      hintTextwayPoint0,
      hintTextwayPoint1,
      hintTextwayPoint2,
      hintTextwayPoint3,
      hintTextwayPoint4,
    ];
    allTextEditingPlaces = [
      wayPoint0Controller,
      wayPoint1Controller,
      wayPoint2Controller,
      wayPoint3Controller,
      wayPoint4Controller,
    ];
    currentLocationToFormPlacesAll = [
      currentLocationToFormPlaces0,
      currentLocationToFormPlaces1,
      currentLocationToFormPlaces2,
      currentLocationToFormPlaces3,
      currentLocationToFormPlaces4,
    ];
    placeListResponseAll = [
      wayPoint0,
      wayPoint1,
      wayPoint2,
      wayPoint3,
      wayPoint4
    ];
    startLocationFromMapAll = [
      startLocationFromMap0,
      startLocationFromMap1,
      startLocationFromMap2,
      startLocationFromMap3,
      startLocationFromMap4,
    ];
    currentLocationStringAll = [
      currentLocationString0,
      currentLocationString1,
      currentLocationString2,
      currentLocationString3,
      currentLocationString4,
    ];
    placesCoordinate = [
      placesCoordinate0,
      placesCoordinate1,
      placesCoordinate2,
      placesCoordinate3,
      placesCoordinate4,
    ];
    update();
  }

  void removeStop(Map<String, dynamic> stop) {
    stopPoints.remove(stop);
    update();
  }

  Future<void> savePlaceToServer(
      String latitude, String longitude, String name, String rate) async {
    var data = {
      'latitude': latitude,
      'longitude': longitude,
      'name': name,
      'rate': rate,
    };
    try {
      CRUD().post(
        link: AppLink.savePlacesServer,
        payload: data,
      );
    } catch (e) {
      Log.print('Error: $e');
    }
  }

  Future<void> getLocation() async {
    Log.print('🛰️ getLocation() called');
    permissionGranted = await location.hasPermission();
    if (permissionGranted == PermissionStatus.denied) {
      permissionGranted = await location.requestPermission();
      if (permissionGranted != PermissionStatus.granted) {
        return;
      }
    }

    // Pre-populate with last known position for instant loading
    try {
      Position? lastPosition = await Geolocator.getLastKnownPosition();
      if (lastPosition != null) {
        passengerLocation =
            LatLng(lastPosition.latitude, lastPosition.longitude);
        newStartPointLocation = passengerLocation;
        newMyLocation = passengerLocation;
        Log.print(
            '📍 Pre-populated location from last known: $passengerLocation');
      }
    } catch (e) {
      Log.print('⚠️ Error getting last known position: $e');
    }

    LocationData? _locationData;
    try {
      _locationData = await location.getLocation().timeout(
        const Duration(seconds: 5),
        onTimeout: () {
          Log.print("⚠️ Location fetch timed out after 5s.");
          return LocationData.fromMap({
            "latitude": passengerLocation.latitude,
            "longitude": passengerLocation.longitude,
            "speed": 0.0
          });
        },
      );
    } catch (e) {
      Log.print("⚠️ Error fetching location: $e");
    }

    if (_locationData == null) {
      isLoading = false;
      update();
      return;
    }
    passengerLocation =
        (_locationData.latitude != null && _locationData.longitude != null
            ? LatLng(_locationData.latitude!, _locationData.longitude!)
            : const LatLng(32, 34));

    newStartPointLocation = passengerLocation;
    newMyLocation = passengerLocation;

    if (Get.isRegistered<RideLifecycleController>()) {
      final rideLifecycle = Get.find<RideLifecycleController>();
      rideLifecycle.getLocationArea(
          passengerLocation.latitude, passengerLocation.longitude);
      rideLifecycle.resetNoRideSearch();
    }

    try {
      getReverseGeocoding(passengerLocation).then((address) {
        currentLocationString = address;
        update();
      });
    } catch (e) {
      Log.print('Error resolving current location: $e');
    }

    OfflineMapService.instance
        .downloadRegion(passengerLocation, radiusKm: 10.0);

    try {
      final mapEngine = Get.find<MapEngineController>();
      if (mapEngine.mapController != null) {
        mapEngine.mapController!.animateCamera(
          CameraUpdate.newLatLng(passengerLocation),
        );
      }
    } catch (e) {
      Log.print('Error animating camera to passenger location: $e');
    }

    speed = _locationData.speed ?? 0.0;
    isLoading = false;
    update();
  }

  void getCurrentLocationFormString() async {
    currentLocationToFormPlaces = true;
    currentLocationString = 'Waiting for your location'.tr;
    await getLocation();
    currentLocationString = passengerLocation.toString();
    newStartPointLocation = passengerLocation;
    update();
  }

  Future<void> getPlaces() async {
    final q = placeDestinationController.text.trim();
    if (q.isEmpty || q.length < 3) {
      placesDestination = [];
      update();
      return;
    }

    final lat = passengerLocation.latitude;
    final lng = passengerLocation.longitude;
    final country = CountryPolygons.getCountryName(passengerLocation);

    try {
      final url =
          '${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=15000&country=$country';
      final response = await CRUD().getMapSaas(link: url);

      if (response != null && response['results'] is List) {
        List results = List.from(response['results']);
        final List filteredResults = [];
        final Set<String> seenPlaces = {};

        for (final p in results) {
          final name = p['name_ar'] ?? p['name'] ?? '';
          final district = p['district'] ?? '';
          final plat = p['latitude']?.toString() ?? '0';
          final plng = p['longitude']?.toString() ?? '0';

          final dedupeKey =
              "${name.trim().toLowerCase()}_${district.trim().toLowerCase()}";

          if (!seenPlaces.contains(dedupeKey)) {
            seenPlaces.add(dedupeKey);

            p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0;
            p['latitude'] = plat;
            p['longitude'] = plng;
            p['name'] = name;
            p['address'] = p['full_address'] ??
                (district.isNotEmpty
                    ? "$district، ${p['governorate'] ?? ''}"
                    : (p['governorate'] ?? ''));

            filteredResults.add(p);
          }
        }

        placesDestination = filteredResults;
        update();
      }
    } catch (e) {
      Log.print('Exception in getPlaces: $e');
    }
  }

  Future<void> getPlacesStart() async {
    final q = placeStartController.text.trim();
    if (q.isEmpty || q.length < 3) {
      placesStart = [];
      update();
      return;
    }

    final lat = passengerLocation.latitude;
    final lng = passengerLocation.longitude;
    final country = CountryPolygons.getCountryName(passengerLocation);

    try {
      final url =
          '${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=15000&country=$country';
      final response = await CRUD().getMapSaas(link: url);

      if (response != null && response['results'] is List) {
        List list = List.from(response['results']);
        for (final p in list) {
          p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0;
          p['latitude'] = p['latitude'].toString();
          p['longitude'] = p['longitude'].toString();
          p['name'] = p['name_ar'] ?? p['name'] ?? '';
          p['address'] = p['full_address'] ??
              (p['district'] != null
                  ? "${p['district']}، ${p['governorate'] ?? ''}"
                  : (p['governorate'] ?? ''));
        }
        placesStart = list;
        update();
      }
    } catch (e) {
      Log.print('Exception in getPlacesStart: $e');
    }
  }

  Future<void> getPlacesListsWayPoint(int index) async {
    final q = wayPoint0Controller.text.trim();
    if (q.length < 3) return;

    final lat = passengerLocation.latitude;
    final lng = passengerLocation.longitude;
    final country = CountryPolygons.getCountryName(passengerLocation);

    try {
      final url =
          '${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=15000&country=$country';
      final response = await CRUD().getMapSaas(link: url);

      if (response != null && response['results'] is List) {
        List list = List.from(response['results']);
        for (final p in list) {
          p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0;
          p['latitude'] = p['latitude'].toString();
          p['longitude'] = p['longitude'].toString();
          p['name'] = p['name_ar'] ?? p['name'] ?? '';
          p['address'] = p['full_address'] ??
              (p['district'] != null
                  ? "${p['district']}، ${p['governorate'] ?? ''}"
                  : (p['governorate'] ?? ''));
        }
        wayPoint0 = list;
        placeListResponseAll[index] = list;
        update();
      }
    } catch (e) {
      Log.print('Error fetching places in WayPoint: $e');
    }
  }

  Future<String> getReverseGeocoding(LatLng location) async {
    final lat = location.latitude;
    final lng = location.longitude;
    final url = '${AppLink.reverseGeocoding}?lat=$lat&lng=$lng';

    try {
      final response = await CRUD().getMapSaas(link: url);

      if (response != null && response is List && response.isNotEmpty) {
        final data = response[0];
        String name = data['name_ar'] ?? data['name'] ?? 'Unknown Location'.tr;
        return name;
      }
      return 'Unknown Location'.tr;
    } catch (e) {
      Log.print('ReverseGeocoding Exception: $e');
      return 'Unknown Location'.tr;
    }
  }

  void updateCurrentLocationFromCamera(LatLng target) {
    Log.print('📍 updateCurrentLocationFromCamera: $target');
    newMyLocation = target;

    if (startLocationFromMap == true) {
      Log.print('📍 Updating startLocationFromMap to $target');
      newStartPointLocation = target;
    } else if (passengerStartLocationFromMap == true) {
      Log.print('📍 Updating passengerStartLocationFromMap to $target');
      newStartPointLocation = target;
    }

    int waypointsLength = Get.find<WayPointController>().wayPoints.length;
    if (waypointsLength > 0 &&
        wayPointIndex >= 0 &&
        wayPointIndex < placesCoordinate.length) {
      Log.print('📍 Updating wayPointIndex $wayPointIndex to $target');
      placesCoordinate[wayPointIndex] =
          '${target.latitude},${target.longitude}';
    }
    if (Get.isRegistered<RideLifecycleController>()) {
      final rideLifecycle = Get.find<RideLifecycleController>();
      rideLifecycle.getLocationArea(target.latitude, target.longitude);
      rideLifecycle.resetNoRideSearch();
    }
    update();
  }

  void onCameraMoveThrottled(CameraPosition pos) {
    _camThrottle?.cancel();
    _camThrottle = Timer(const Duration(milliseconds: 160), () {
      Log.print('📸 onCameraMoveThrottled: ${pos.target}');
      int waypointsLength = Get.find<WayPointController>().wayPoints.length;
      int index = wayPointIndex;
      if (waypointsLength > 0 && index < placesCoordinate.length) {
        placesCoordinate[index] =
            '${pos.target.latitude},${pos.target.longitude}';
      }
      newMyLocation = pos.target;
    });
  }

  void convertHintTextPlaces(int index, var res) {
    if (placeListResponseAll[index].isEmpty) {
      placeListResponseAll[index] = res;
      hintTextwayPointStringAll[index] = 'Search for your Start point'.tr;
      update();
    } else {
      hintTextwayPointStringAll[index] = res['name'];
      currentLocationStringAll[index] = res['name'];
      placesCoordinate[index] =
          '${res['geometry']['location']['lat']},${res['geometry']['location']['lng']}';
      placeListResponseAll[index] = [];
      allTextEditingPlaces[index].clear();
      update();
      Get.back();
    }
  }

  void convertHintTextDestinationNewPlaces(int index) {
    if (placesDestination.isEmpty) {
      hintTextDestinationPoint = 'Search for your destination'.tr;
      update();
    } else {
      var res = placesDestination[index];
      hintTextDestinationPoint = res['displayName']?['text'] ??
          res['formattedAddress'] ??
          res['name'] ??
          'Unknown Place';
      double? lat = res['location']?['latitude'] ??
          double.tryParse(res['latitude']?.toString() ?? '');
      double? lng = res['location']?['longitude'] ??
          double.tryParse(res['longitude']?.toString() ?? '');

      if (lat != null && lng != null) {
        newMyLocation = LatLng(lat, lng);
        final mapEngine = Get.find<MapEngineController>();
        mapEngine.mapController
            ?.animateCamera(CameraUpdate.newLatLngZoom(newMyLocation, 16));
      }
      update();
    }
  }

  void convertHintTextDestinationNewPlacesFromRecent(
      List recentLocations, int index) {
    hintTextDestinationPoint = recentLocations[index]['name'];
    double lat = recentLocations[index]['latitude'];
    double lng = recentLocations[index]['longitude'];
    newMyLocation = LatLng(lat, lng);

    final mapEngine = Get.find<MapEngineController>();
    mapEngine.mapController
        ?.animateCamera(CameraUpdate.newLatLngZoom(newMyLocation, 16));
    update();
  }

  void clearPlacesDestination() {
    placesDestination = [];
    hintTextDestinationPoint = 'Search for your destination'.tr;
    update();
  }

  void clearPlacesStart() {
    placesStart = [];
    hintTextStartPoint = 'Search for your Start point'.tr;
    update();
  }

  void clearPlaces(int index) {
    placeListResponseAll[index] = [];
    hintTextwayPointStringAll[index] = 'Search for waypoint'.tr;
    update();
  }

  Future<Map<String, double>?> extractCoordinatesFromLinkAsync(
      String link) async {
    try {
      if (link.startsWith('geo:') || link.startsWith('google.navigation:')) {
        RegExp regex = RegExp(r'(-?\d+\.\d+)[,/~=](-?\d+\.\d+)');
        var match = regex.firstMatch(link);
        if (match != null) {
          double lat = double.parse(match.group(1)!);
          double lng = double.parse(match.group(2)!);
          if (lat > 40 && lat > lng) {
            double temp = lat;
            lat = lng;
            lng = temp;
          }
          return {'latitude': lat, 'longitude': lng};
        }
      }

      int urlStartIndex = link.indexOf(RegExp(r'https?://'));
      if (urlStartIndex == -1) return null;
      String cleanLink = link.substring(urlStartIndex).trim();

      Uri uri = Uri.parse(cleanLink);
      String finalUrl = cleanLink;

      if (cleanLink.contains('goo.gl') ||
          cleanLink.contains('maps.google.com')) {
        try {
          var response =
              await http.get(uri).timeout(const Duration(seconds: 5));
          finalUrl = response.request?.url.toString() ?? cleanLink;
        } catch (e) {
          Log.print('Redirect logic failed, using original: $e');
        }
      }

      RegExp regex = RegExp(r'(-?\d+\.\d+)[,/~](-?\d+\.\d+)');
      var match = regex.firstMatch(finalUrl);

      if (match != null) {
        double lat = double.parse(match.group(1)!);
        double lng = double.parse(match.group(2)!);

        if (lat > 40 && lat > lng) {
          Log.print("⚠️ Detected Swapped Coordinates in Link. Correcting...");
          double temp = lat;
          lat = lng;
          lng = temp;
        }

        return {
          'latitude': lat,
          'longitude': lng,
        };
      }
    } catch (e) {
      Log.print('Error parsing location link: $e');
    }
    return null;
  }

  void handleWhatsAppLink(String link) async {
    Map<String, double>? coordinates =
        await extractCoordinatesFromLinkAsync(link);

    if (coordinates != null) {
      latitudeWhatsApp = coordinates['latitude']!;
      longitudeWhatsApp = coordinates['longitude']!;
      Log.print(
          'Extracted coordinates: Lat: $latitudeWhatsApp, Long: $longitudeWhatsApp');
    } else {
      Log.print('Failed to extract coordinates from the link');
    }
  }

  void goToWhatappLocation() async {
    if (sosFormKey.currentState!.validate()) {
      Map<String, double>? coordinates =
          await extractCoordinatesFromLinkAsync(whatsAppLocationText.text);

      if (coordinates != null) {
        latitudeWhatsApp = coordinates['latitude']!;
        longitudeWhatsApp = coordinates['longitude']!;

        Log.print(
            '📍 Final Coordinates for OSM: Lat: $latitudeWhatsApp, Lng: $longitudeWhatsApp');

        final mapEngine = Get.find<MapEngineController>();
        mapEngine.changeIsWhatsAppOrder(true);
        Get.back();

        myDestination = LatLng(latitudeWhatsApp, longitudeWhatsApp);

        if (passengerLocation != null) {
          await mapEngine.mapController?.animateCamera(CameraUpdate.newLatLng(
              LatLng(passengerLocation.latitude, passengerLocation.longitude)));
        }

        mapEngine.changeMainBottomMenuMap();
        passengerStartLocationFromMap = true;
        mapEngine.isPickerShown = true;
        update();
      } else {
        mySnackbarWarning('لم نتمكن من استخراج الموقع من الرابط');
      }
    }
  }

  void addMenuWaypoint() {
    if (activeMenuWaypointCount >= 2) return;
    activeMenuWaypointCount++;
    final mapEngine = Get.find<MapEngineController>();
    mapEngine.mainBottomMenuMapHeight =
        Get.height * .6 + (activeMenuWaypointCount * 56);
    update();
  }

  void removeMenuWaypoint(int index) {
    if (index < 0 || index >= 2) return;
    if (index == 0 && activeMenuWaypointCount == 2) {
      menuWaypoints[0] = menuWaypoints[1];
      menuWaypointNames[0] = menuWaypointNames[1];
    }
    menuWaypoints[activeMenuWaypointCount - 1] = null;
    menuWaypointNames[activeMenuWaypointCount - 1] = '';
    activeMenuWaypointCount--;
    final mapEngine = Get.find<MapEngineController>();
    mapEngine.mainBottomMenuMapHeight =
        Get.height * .6 + (activeMenuWaypointCount * 56);
    update();
  }

  void clearAllMenuWaypoints() {
    menuWaypoints = [null, null];
    menuWaypointNames = ['', ''];
    activeMenuWaypointCount = 0;
    isPickingWaypoint = false;
    pickingWaypointIndex = -1;
    update();
  }

  void startPickingWaypointOnMap(int index) {
    pickingWaypointIndex = index;
    isPickingWaypoint = true;
    final mapEngine = Get.find<MapEngineController>();
    mapEngine.isPickerShown = true;
    mapEngine.heightPickerContainer = 150;
    mapEngine.isMainBottomMenuMap = true;
    mapEngine.mainBottomMenuMapHeight = Get.height * .22;
    update();
  }

  void setMenuWaypointFromMap(int index, LatLng position) {
    Log.print('📍 setMenuWaypointFromMap called: index=$index, pos=$position');
    if (index < 0 || index >= 2) return;
    menuWaypoints[index] = position;
    menuWaypointNames[index] =
        '${position.latitude.toStringAsFixed(4)}, ${position.longitude.toStringAsFixed(4)}';
    isPickingWaypoint = false;
    pickingWaypointIndex = -1;
    final mapEngine = Get.find<MapEngineController>();
    mapEngine.isPickerShown = false;
    mapEngine.isMainBottomMenuMap = false;
    mapEngine.mainBottomMenuMapHeight =
        Get.height * .6 + (activeMenuWaypointCount * 56);
    update();
  }

  void setMenuWaypointFromSearch(int index, LatLng pos, String name) {
    if (index < 0 || index >= 2) return;
    menuWaypoints[index] = pos;
    menuWaypointNames[index] = name;
    update();
  }

  String buildOsrmWaypointCoords() {
    String coords = '';
    for (int i = 0; i < activeMenuWaypointCount; i++) {
      final wp = menuWaypoints[i];
      if (wp != null) {
        coords += ';${wp.longitude},${wp.latitude}';
      }
    }
    return coords;
  }

  void changeHeightPointsPageForRider() {
    final mapEngine = Get.find<MapEngineController>();
    mapEngine.isPointsPageForRider = !mapEngine.isPointsPageForRider;
    mapEngine.heightPointsPageForRider =
        mapEngine.isPointsPageForRider == true ? Get.height : 0;
    update();
  }

  getCoordinateFromMapWayPoints(int index) {
    placesCoordinate[index] = newStartPointLocation.toString();
    update();
  }

  void addWaypoint(Map<String, dynamic> placeDetails) {
    waypoints.add(placeDetails);
    update();
  }

  void removeWaypoint(int index) {
    if (index >= 0 && index < waypoints.length) {
      waypoints.removeAt(index);
      update();
    }
  }

  getFavioratePlaces() async {
    recentPlaces = await sql.getCustomQuery(
        'SELECT * FROM ${TableName.recentLocations} ORDER BY createdAt DESC');
    update();
  }

  void _listenForDeepLink() {
    ever(_deepLinkController.rawDeepLink, (String? link) async {
      if (link != null && link.isNotEmpty) {
        Log.print('📍 MapPassengerController processing link: $link');

        Map<String, double>? coordinates =
            await extractCoordinatesFromLinkAsync(link);

        if (coordinates != null) {
          double destLat = coordinates['latitude']!;
          double destLng = coordinates['longitude']!;
          myDestination = LatLng(destLat, destLng);

          if (passengerLocation == null ||
              (passengerLocation.latitude == 0 &&
                  passengerLocation.longitude == 0)) {
            Log.print('⏳ Waiting for current location to calculate route...');
            await getLocation();
          }

          if (passengerLocation != null) {
            String originStr =
                '${passengerLocation.latitude},${passengerLocation.longitude}';
            String destStr = '$destLat,$destLng';

            Log.print(
                '🚀 Drawing route from Deep Link: $originStr to $destStr');

            final mapEngine = Get.find<MapEngineController>();
            mapEngine.clearPolyline();
            waypoints.clear();
            clearAllMenuWaypoints();

            final rideLife = Get.find<RideLifecycleController>();
            await rideLife.getDirectionMap(originStr, destStr);

            mapEngine.isBottomSheetShown = true;
            mapEngine.heightBottomSheetShown = 250;
            update();

            Get.snackbar(
              'Location Received'.tr,
              'Route and prices have been calculated successfully!'.tr,
              backgroundColor: AppColor.greenColor,
              colorText: Colors.white,
            );
          }
        } else {
          Log.print('⚠️ Could not extract valid coordinates from link: $link');
        }

        _deepLinkController.rawDeepLink.value = null;
      }
    });

    if (_deepLinkController.rawDeepLink.value != null &&
        _deepLinkController.rawDeepLink.value!.isNotEmpty) {
      String link = _deepLinkController.rawDeepLink.value!;
      _deepLinkController.rawDeepLink.value = null;

      Future.delayed(const Duration(milliseconds: 500), () async {
        Log.print(
            '📍 MapPassengerController processing link (Cold Start): $link');

        Map<String, double>? coordinates =
            await extractCoordinatesFromLinkAsync(link);

        if (coordinates != null) {
          double destLat = coordinates['latitude']!;
          double destLng = coordinates['longitude']!;
          myDestination = LatLng(destLat, destLng);

          if (passengerLocation == null ||
              (passengerLocation.latitude == 0 &&
                  passengerLocation.longitude == 0)) {
            await getLocation();
          }

          if (passengerLocation != null) {
            String originStr =
                '${passengerLocation.latitude},${passengerLocation.longitude}';
            String destStr = '$destLat,$destLng';

            final mapEngine = Get.find<MapEngineController>();
            mapEngine.clearPolyline();
            waypoints.clear();
            clearAllMenuWaypoints();

            final rideLife = Get.find<RideLifecycleController>();
            await rideLife.getDirectionMap(originStr, destStr);

            mapEngine.isBottomSheetShown = true;
            mapEngine.heightBottomSheetShown = 250;
            update();
          }
        }
      });
    }
  }

  // --- Polygon Math and University Check Methods ---
  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];

      if (_rayIntersectsSegment(point, vertex1, vertex2)) {
        intersections++;
      }
    }
    return intersections % 2 != 0;
  }

  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;

    if ((py < v1y && py < v2y) || (py > v1y && py > v2y)) {
      return false;
    }

    double intersectX = v1x + (py - v1y) * (v2x - v1x) / (v2y - v1y);
    return intersectX > px;
  }

  String checkPassengerLocation(LatLng passengerLocation,
      List<List<LatLng>> universityPolygons, List<String> universityNames) {
    for (int i = 0; i < universityPolygons.length; i++) {
      if (isPointInPolygon(passengerLocation, universityPolygons[i])) {
        isInUniversity = true;
        return "Passenger is in ${universityNames[i]}";
      }
    }
    return "Passenger is not in any university";
  }

  void getPassengerLocationUniversity() {
    passengerLocationStringUnvirsity = checkPassengerLocation(
      passengerLocation,
      UniversitiesPolygons.universityPolygons,
      UniversitiesPolygons.universityNames,
    );
    Log.print(passengerLocationStringUnvirsity);
  }

  void getMapPointsForAllMethods() async {
    final mapEngine = Get.find<MapEngineController>();
    final rideLife = Get.find<RideLifecycleController>();

    mapEngine.clearPolyline();
    mapEngine.isMarkersShown = false;
    mapEngine.isWayPointStopsSheetUtilGetMap = false;
    mapEngine.isWayPointSheet = false;
    rideLife.durationToRide = 0;
    rideLife.distanceOfDestination = 0;
    mapEngine.wayPointSheetHeight = 0;
    rideLife.remainingTime = 25;
    rideLife.haveSteps = true;

    // Filter out empty value
    coordinatesWithoutEmpty =
        placesCoordinate.where((coord) => coord.isNotEmpty).toList();
    latestPosition = LatLng(
        double.parse(coordinatesWithoutEmpty.last.split(',')[0]),
        double.parse(coordinatesWithoutEmpty.last.split(',')[1]));
    for (var i = 0; i < coordinatesWithoutEmpty.length; i++) {
      if ((i + 1) < coordinatesWithoutEmpty.length) {
        await rideLife.getMapPoints(
          coordinatesWithoutEmpty[i].toString(),
          coordinatesWithoutEmpty[i + 1].toString(),
          i,
        );
        if (i == 0) {
          startNameAddress = rideLife.data[0]['start_address'];
        }
        if (i == coordinatesWithoutEmpty.length - 1) {
          endNameAddress = rideLife.data[0]['end_address'];
        }
      }
    }

    if (rideLife.haveSteps) {
      String latestWaypoint =
          placesCoordinate.lastWhere((coord) => coord.isNotEmpty);
      update();
    }
  }

  double _haversineKm(double lat1, double lon1, double lat2, double lon2) {
    const double r = 6371.0;
    double dLat = (lat2 - lat1) * pi / 180.0;
    double dLon = (lon2 - lon1) * pi / 180.0;
    double a = sin(dLat / 2) * sin(dLat / 2) +
        cos(lat1 * pi / 180.0) *
            cos(lat2 * pi / 180.0) *
            sin(dLon / 2) *
            sin(dLon / 2);
    double c = 2 * atan2(sqrt(a), sqrt(1 - a));
    return r * c;
  }

  double _kmToLatDelta(double km) {
    return km / 111.0;
  }

  double _kmToLngDelta(double km, double lat) {
    return km / (111.0 * cos(lat * pi / 180.0));
  }

  String _buildOsrmWaypointCoords() {
    String coords = '';
    for (int i = 0; i < activeMenuWaypointCount; i++) {
      final wp = menuWaypoints[i];
      if (wp != null) {
        coords += ';${wp.longitude},${wp.latitude}';
      }
    }
    return coords;
  }

  @override
  void onClose() {
    _camThrottle?.cancel();
    super.onClose();
  }
}
