import 'dart:io'; import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:nearle/background/backgroundservice.dart'; /// Helper class to schedule/cancel shift end alarms /// Works even when app is killed (uses Android AlarmManager) class ShiftEndAlarm { static const MethodChannel _channel = MethodChannel('nearle/shift_end'); /// Schedule an alarm for shift end time /// This alarm will fire even if the app is killed /// If shift end time has already passed today, it will trigger immediately static Future scheduleAlarm({ required String endTime, // Format: "HH:mm:ss" or "HH:mm" String startTime = '', // Format: "HH:mm:ss" or "HH:mm" (for overnight shift detection) }) async { if (!Platform.isAndroid) { debugPrint('[SHIFT_END_ALARM] Only supported on Android'); return false; } try { debugPrint('[SHIFT_END_ALARM] 📅 scheduleAlarm called - endTime: "$endTime", startTime: "$startTime"'); // Check if shift end time has already passed today final now = DateTime.now(); debugPrint('[SHIFT_END_ALARM] 📅 Current time: ${now.toString()}'); final endParts = endTime.split(':'); if (endParts.length >= 2) { final int endHour = int.tryParse(endParts[0]) ?? 0; final int endMinute = int.tryParse(endParts[1]) ?? 0; final int endSecond = endParts.length > 2 ? (int.tryParse(endParts[2]) ?? 0) : 0; final DateTime endToday = DateTime( now.year, now.month, now.day, endHour, endMinute, endSecond, ); debugPrint('[SHIFT_END_ALARM] 📅 Shift end time today: ${endToday.toString()}'); debugPrint('[SHIFT_END_ALARM] 📅 Time comparison: now.isAfter(endToday) = ${now.isAfter(endToday)}'); // If shift end time has passed, trigger immediately if (now.isAfter(endToday) || now.isAtSameMomentAs(endToday)) { debugPrint('[SHIFT_END_ALARM] ⚡ Shift end time ($endTime) has already passed - triggering break log immediately'); await handleShiftEnd(); } else { debugPrint('[SHIFT_END_ALARM] ⏰ Shift end time ($endTime) has not passed yet - will schedule alarm'); } } else { debugPrint('[SHIFT_END_ALARM] ⚠️ Invalid endTime format: "$endTime"'); } final result = await _channel.invokeMethod( 'scheduleShiftEndAlarm', { 'endTime': endTime, 'startTime': startTime, }, ); final success = result ?? false; if (success) { debugPrint('[SHIFT_END_ALARM] ✅ Successfully scheduled alarm for shift end: $endTime'); } else { debugPrint('[SHIFT_END_ALARM] ⚠️ Failed to schedule alarm for shift end: $endTime'); } return success; } on PlatformException catch (e) { debugPrint('[SHIFT_END_ALARM] ❌ Error scheduling alarm: ${e.message}'); return false; } catch (e) { debugPrint('[SHIFT_END_ALARM] ❌ Unexpected error: $e'); return false; } } /// Cancel the scheduled shift end alarm static Future cancelAlarm() async { if (!Platform.isAndroid) { return false; } try { final result = await _channel.invokeMethod('cancelShiftEndAlarm'); debugPrint('[SHIFT_END_ALARM] ✅ Cancelled shift end alarm'); return result ?? false; } on PlatformException catch (e) { debugPrint('[SHIFT_END_ALARM] ❌ Error cancelling alarm: ${e.message}'); return false; } catch (e) { debugPrint('[SHIFT_END_ALARM] ❌ Unexpected error: $e'); return false; } } /// Handle shift end when alarm fires (called by BroadcastReceiver) /// This will create the break log and set rider offline static Future handleShiftEnd() async { try { debugPrint('[SHIFT_END_ALARM] 🔔 Shift end alarm fired - creating break log...'); final prefs = await SharedPreferences.getInstance(); // Check if still on duty (might have been manually set offline) final int onduty = prefs.getInt('onduty') ?? 0; if (onduty != 1) { debugPrint('[SHIFT_END_ALARM] Already offline, skipping break log creation'); return; } // Call the background service to create break log // This will create break log and set offline await BackgroundDeliveryLog.checkShiftEnd(); debugPrint('[SHIFT_END_ALARM] ✅ Break log created successfully'); } catch (e) { debugPrint('[SHIFT_END_ALARM] ❌ Error handling shift end: $e'); } } }