import 'package:get/get.dart'; import 'dart:async'; import '../../../models/patient_model.dart'; import '../../../models/device_model.dart'; import '../../../models/realtime_monitoring_model.dart'; import '../../../models/history_model.dart'; import '../../../models/chart_data_point.dart'; import '../../../services/firestore_service.dart'; import '../../../services/realtime_database_service.dart'; import '../../../widgets/app_snackbar.dart'; class DeviceDetailController extends GetxController { final FirestoreService _firestoreService = FirestoreService(); final RealtimeDatabaseService _realtimeService = RealtimeDatabaseService(); String? deviceId; String? roomId; final deviceName = ''.obs; final patientName = ''.obs; final roomName = ''.obs; final dropsPerMinute = '0'.obs; final lastUpdate = DateTime.now().obs; final isServoActive = false.obs; final deviceStatus = 'disconnected'.obs; final isLoading = true.obs; final RxList chartData = [].obs; StreamSubscription? _realtimeSubscription; StreamSubscription? _historySubscription; PatientModel? patient; DeviceModel? device; RealtimeMonitoringModel? realtimeData; @override void onInit() { super.onInit(); _getArguments(); if (deviceId != null && roomId != null) { _initializeDeviceDetail(); } else { Get.back(); AppSnackbar.error('Device ID tidak ditemukan'); } } @override void onClose() { _realtimeSubscription?.cancel(); _historySubscription?.cancel(); super.onClose(); } void _getArguments() { final args = Get.arguments as Map?; if (args != null) { deviceId = args['deviceId']; roomId = args['roomId']; } } Future _initializeDeviceDetail() async { try { isLoading.value = true; await _loadPatientData(); await _loadDeviceData(); _listenToRealtimeData(); _listenToHistoryData(); isLoading.value = false; } catch (e) { isLoading.value = false; AppSnackbar.error('Gagal memuat data'); } } Future _loadPatientData() async { patient = await _firestoreService.getPatientByDeviceId(deviceId!); if (patient != null) { patientName.value = patient!.namePatient; } } Future _loadDeviceData() async { device = await _firestoreService.getDeviceById(deviceId!); if (device != null) { deviceName.value = device!.devicesName; roomName.value = await _getRoomName(device!.roomId); } } Future _getRoomName(String roomId) async { try { final rooms = await _firestoreService.getRoomsStream().first; final room = rooms.firstWhereOrNull( (r) => r.id == roomId || r.roomName.toLowerCase() == roomId.toLowerCase(), ); return room?.roomName ?? roomId; } catch (e) { return roomId; } } void _listenToRealtimeData() { final dbRoomId = roomId!.toLowerCase().replaceAll(' ', '_'); _realtimeSubscription = _realtimeService .getDeviceStream(dbRoomId, deviceId!) .listen((data) { if (data != null) { realtimeData = data; dropsPerMinute.value = data.dropRate.toStringAsFixed(0); lastUpdate.value = data.lastUpdate; isServoActive.value = data.servoOpen; deviceStatus.value = data.deviceStatus; } }, onError: (error) => AppSnackbar.error('Koneksi realtime terputus')); } void _listenToHistoryData() { _historySubscription = _firestoreService .getDeviceHistoriesStream(deviceId!) .listen( (histories) { if (histories.isNotEmpty) { _processHistoryData(histories); } else { chartData.value = []; } }, onError: (error) { chartData.value = []; AppSnackbar.error('Gagal memuat data history'); }, ); } void _processHistoryData(List histories) { histories.sort((a, b) => b.timestamp.compareTo(a.timestamp)); final latestHistories = histories.take(10).toList(); latestHistories.sort((a, b) => a.timestamp.compareTo(b.timestamp)); final List points = latestHistories.map((history) { return ChartDataPoint( hour: history.timestamp.hour, dropsPerMinute: history.dropPerMinute, ); }).toList(); chartData.value = points; } Future toggleServo(bool value) async { try { final dbRoomId = roomId!.toLowerCase().replaceAll(' ', '_'); await _realtimeService.controlServo(dbRoomId, deviceId!, value); isServoActive.value = value; AppSnackbar.success(value ? 'Infus dibuka' : 'Infus ditutup'); } catch (e) { AppSnackbar.error('Gagal mengontrol servo'); } } String getLastUpdateText() { final difference = DateTime.now().difference(lastUpdate.value); if (difference.inMinutes < 1) return 'just now'; if (difference.inMinutes < 60) return '${difference.inMinutes}m ago'; if (difference.inHours < 24) return '${difference.inHours}h ago'; return '${difference.inDays}d ago'; } void navigateToHistory() { Get.toNamed( '/history', arguments: { 'deviceId': deviceId, 'deviceName': deviceName.value, 'patientName': patientName.value, }, ); } Future refreshData() async { await _loadDeviceData(); } }