import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intaleq_maps/intaleq_maps.dart'; import '../services/offline_routing_engine.dart'; import '../services/tactical_api_service.dart'; import '../services/turn_by_turn_navigation_engine.dart'; /// ============================================================================ /// [NavigationController] - وحدة التحكم بالملاحة وتوجيه القوافل التكتيكية /// ============================================================================ /// English: /// GetX Controller managing hybrid tactical convoy routing (Online API + Sovereign /// Offline Engine fallback), active turn-by-turn guidance, and navigation metrics. /// /// العربية: /// متحكم GetX لإدارة توجيه القوافل والآليات العسكرية (هجين: سيرفر أونلاين + محرك أوفلاين محلي)، /// وتتبع مسار الملاحة خطوة بخطوة وحساب السرعة والوقت المتبقي للهدف. /// ============================================================================ class NavigationController extends GetxController { // ── Observables / الحالات التفاعلية ────────────────────────────────────── final Rx activeRoute = Rx(null); final Rx vehicleProfile = Rx(TacticalVehicleProfile.convoy); final RxBool isCalculating = false.obs; /// Calculate Hybrid Tactical Route / احتساب مسار تكتيكي هجين (سيرفر + محلي) Future calculateRoute({ required LatLng origin, required LatLng destination, TacticalVehicleProfile? profile, bool autoStart = false, IntaleqMapController? mapController, }) async { final activeProfile = profile ?? vehicleProfile.value; vehicleProfile.value = activeProfile; isCalculating.value = true; OfflineRoutePlan? plan; // 1. Try Online NestJS Server Routing API try { final serverRoute = await TacticalApiService.calculateTacticalRoute( origin: origin, destination: destination, profile: activeProfile.name, ); if (serverRoute != null && serverRoute.points.isNotEmpty) { plan = OfflineRoutePlan( polylinePoints: serverRoute.points, totalDistanceKm: serverRoute.distanceKm, estimatedDurationMinutes: serverRoute.durationMinutes, profile: activeProfile, tacticalWaypoints: const ['موقع الانطلاق', 'الهدف التكتيكي المحدد'], isOffline: false, ); } } catch (e) { debugPrint('Online route fallback: $e'); } // 2. Fallback to 100% Sovereign On-Device Offline Routing Engine plan ??= OfflineRoutingEngine.calculateOnDeviceRoute( start: origin, destination: destination, profile: activeProfile, ); activeRoute.value = plan; isCalculating.value = false; if (autoStart) { startNavigation(mapController: mapController); } return plan; } /// Start Active Turn-by-Turn Guidance / بدء الإرشاد الملاحي الحي void startNavigation({IntaleqMapController? mapController}) { if (activeRoute.value == null) return; TurnByTurnNavigationEngine.startNavigation( plan: activeRoute.value!, simulate: false, controller: mapController, ); } /// Stop Navigation / إنهاء الملاحة void stopNavigation() { TurnByTurnNavigationEngine.stopNavigation(); } /// Reset Route State / إعادة ضبط المسار void reset() { stopNavigation(); activeRoute.value = null; } }