import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter_foreground_task/flutter_foreground_task.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:nearle/providers/deliverylog/deliverylog_provider.dart'; import 'package:nearle/views/helpers/constants/apiconstants.dart'; import 'package:nearle/background/foreground_service.dart' as fg; import 'package:geolocator/geolocator.dart'; /// Controller for managing active delivery logs /// Now delegates to the background service for actual logging class LogController extends GetxController { final CreateDeliveryLogProvider _logProvider = CreateDeliveryLogProvider(); static const String _offlineLogKey = 'offline_delivery_logs'; bool _isFlushing = false; /// Start the delivery log streaming service (via foreground service) Future startLogging() async { debugPrint('[ACTIVE_DELIVERY_LOG] Requesting start logging...'); // Attempt to flush offline logs on start flushOfflineLogs(); // Only show foreground notification when rider is actually on duty try { final prefs = await SharedPreferences.getInstance(); final int onduty = prefs.getInt('onduty') ?? 0; if (onduty != 1) { debugPrint( '[ACTIVE_DELIVERY_LOG] Skipping startLogging because onduty=$onduty', ); return; } } catch (_) { // If prefs fail, continue with best-effort start } if (Platform.isAndroid) { if (await FlutterForegroundTask.isRunningService) { debugPrint('[ACTIVE_DELIVERY_LOG] Foreground service already running'); return; } debugPrint( '[ACTIVE_DELIVERY_LOG] Starting foreground service for delivery logs', ); FlutterForegroundTask.init( androidNotificationOptions: AndroidNotificationOptions( channelId: 'nearle_bg_service', channelName: 'Background Service', channelDescription: 'Keeps Nearle online updates running in background.', channelImportance: NotificationChannelImportance.LOW, priority: NotificationPriority.LOW, ), iosNotificationOptions: const IOSNotificationOptions( showNotification: true, playSound: false, ), foregroundTaskOptions: ForegroundTaskOptions( interval: 30000, // 30 seconds isOnceEvent: false, autoRunOnBoot: false, allowWakeLock: true, allowWifiLock: true, ), ); // Check permissions before starting service to prevent Android 14 crash final permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) { debugPrint( '[ACTIVE_DELIVERY_LOG] Location permission missing, skipping service start', ); return; } try { await FlutterForegroundTask.startService( notificationTitle: 'Nearle is running', notificationText: 'You are Currently on Duty !', callback: fg.riderLogCallback, ); } catch (e) { debugPrint('[ACTIVE_DELIVERY_LOG] Failed to start service: $e'); } } else { debugPrint( '[ACTIVE_DELIVERY_LOG] iOS/Web not fully supported for background service yet', ); } } /// Stop the delivery log streaming service /// Note: This might stop rider logs too if they share the service. /// Usually we only stop if the user goes off-duty or logs out. void stopLogging() { debugPrint( '[ACTIVE_DELIVERY_LOG] Stop logging requested (no-op to preserve rider logs)', ); // We do not stop the service here because it might be running for Rider Logs. // The service should be stopped by RiderLogController when going off-duty. } // ---------------- Offline Queue Logic (Foreground Helper) ---------------- /// Call this on app start or network restoration Future flushOfflineLogs() async { if (_isFlushing) return; _isFlushing = true; try { final prefs = await SharedPreferences.getInstance(); final List queue = prefs.getStringList(_offlineLogKey) ?? []; if (queue.isEmpty) return; debugPrint( '[ACTIVE_DELIVERY_LOG][OFFLINE] Flushing ${queue.length} offline logs...', ); final List remaining = []; bool anySuccess = false; // Determine API endpoint final url = ApiConstants.mainRoute == 'live' ? ApiConstants.createDeliveryLogLive : ApiConstants.createDeliveryLogDev; for (final itemStr in queue) { try { final Map item = jsonDecode(itemStr); final String orderId = item['orderId'] ?? ''; final Map payload = Map.from( item['payload'] ?? {}, ); if (payload.isEmpty) continue; debugPrint( '[ACTIVE_DELIVERY_LOG][OFFLINE] Retrying for orderId: $orderId', ); final result = await _logProvider .createDeliveryLog(url, payload) .timeout(const Duration(seconds: 8)); if (result != null) { debugPrint( '[ACTIVE_DELIVERY_LOG][OFFLINE] Success for orderId: $orderId', ); anySuccess = true; } else { remaining.add(itemStr); } } catch (e) { debugPrint( '[ACTIVE_DELIVERY_LOG][OFFLINE] Error processing item: $e', ); remaining.add(itemStr); } } if (anySuccess || remaining.length != queue.length) { await prefs.setStringList(_offlineLogKey, remaining); debugPrint( '[ACTIVE_DELIVERY_LOG][OFFLINE] Flush complete. Remaining: ${remaining.length}', ); } } catch (e) { debugPrint('[ACTIVE_DELIVERY_LOG][OFFLINE] Flush error: $e'); } finally { _isFlushing = false; } } }