import 'package:get/get.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_database/firebase_database.dart'; import '../../../services/firestore_service.dart'; import '../../../services/realtime_database_service.dart'; import '../../../models/patient_model.dart'; import '../../../models/device_model.dart'; import '../../../models/room_model.dart'; import '../../../widgets/app_snackbar.dart'; class Patient { final String id; final String name; final String room; final String deviceId; final String guardian; final String email; final String? userId; final String status; Patient({ required this.id, required this.name, required this.room, required this.deviceId, required this.guardian, required this.email, this.userId, this.status = 'Aktif', }); Map toFirestore() { return { 'name_patient': name, 'name_guardian': guardian, 'device_id': deviceId, 'room_id': room, 'user_id': userId, }; } factory Patient.fromFirestore(DocumentSnapshot doc) { final data = doc.data() as Map; return Patient( id: doc.id, name: data['name_patient'] ?? '', guardian: data['name_guardian'] ?? '', deviceId: data['device_id'] ?? '', room: data['room_id'] ?? '', email: '', userId: data['user_id'], ); } } class ProfileController extends GetxController { final FirestoreService _firestoreService = FirestoreService(); final RealtimeDatabaseService _realtimeService = RealtimeDatabaseService(); final patients = [].obs; final isLoading = false.obs; @override void onInit() { super.onInit(); _listenToPatients(); } void refreshPatients() { _listenToPatients(); } void _listenToPatients() { _firestoreService.getPatientsStream().listen((patientModels) async { final patientsWithEmail = []; for (var model in patientModels) { try { final email = await _getGuardianEmail(model.nameGuardian); final roomName = await _getRoomName(model.roomId); patientsWithEmail.add( Patient( id: model.id, name: model.namePatient, guardian: model.nameGuardian, deviceId: model.deviceId, room: roomName, email: email, userId: null, ), ); } catch (e) { continue; } } patients.value = patientsWithEmail; }, onError: (error) => AppSnackbar.error('Gagal memuat data')); } Future _getGuardianEmail(String guardianName) async { try { final userDoc = await FirebaseFirestore.instance .collection('users') .where('role', isEqualTo: 'guardian') .where('name', isEqualTo: guardianName) .limit(1) .get(); return userDoc.docs.isNotEmpty ? userDoc.docs.first.data()['email'] ?? '' : ''; } catch (e) { return ''; } } Future _getRoomName(String roomId) async { try { final roomDoc = await FirebaseFirestore.instance .collection('rooms') .doc(roomId) .get(); return roomDoc.data()?['room_name'] ?? roomId; } catch (e) { return roomId; } } Future addPatient({ required String patientName, required String guardianName, required String roomName, required String deviceId, required String email, required String password, }) async { try { isLoading.value = true; if (!await _validateNewPatient(email, deviceId)) return; final roomId = _generateRoomId(roomName); // PERBAIKAN: Tambahkan device_id saat create user final userId = await _firestoreService.createUser( email: email, password: password, name: guardianName, role: 'guardian', deviceId: deviceId, // ✅ TAMBAHKAN INI ); if (userId == null) throw Exception('Gagal membuat user'); await _ensureRoomExists(roomId, roomName); await _createDevice(deviceId, roomId); await _firestoreService.createPatient( PatientModel( id: '', namePatient: patientName, nameGuardian: guardianName, deviceId: deviceId, roomId: roomId, ), ); await _realtimeService.updateDeviceStatus(roomId, deviceId, 'connected'); await _createDeviceInRealtimeDB(roomId, deviceId); Get.back(); AppSnackbar.success('Pasien berhasil ditambahkan'); } catch (e) { AppSnackbar.error('Gagal menambahkan pasien: $e'); } finally { isLoading.value = false; } } Future _validateNewPatient(String email, String deviceId) async { if (await _firestoreService.userExists(email)) { AppSnackbar.warning('Email sudah terdaftar'); return false; } if (await _firestoreService.deviceExists(deviceId)) { AppSnackbar.warning('Device ID sudah terdaftar'); return false; } if (await _firestoreService.patientExistsByDevice(deviceId)) { AppSnackbar.warning('Device sudah digunakan'); return false; } return true; } Future updatePatient({ required String patientId, required String patientName, required String guardianName, required String roomName, required String deviceId, required String email, String? newPassword, }) async { try { isLoading.value = true; final oldPatient = await _firestoreService.getPatientById(patientId); if (oldPatient == null) throw Exception('Pasien tidak ditemukan'); final roomId = _generateRoomId(roomName); if (deviceId != oldPatient.deviceId) { if (await _firestoreService.deviceExists(deviceId)) { AppSnackbar.warning('Device ID sudah terdaftar'); return; } } await _firestoreService.updatePatient( patientId, PatientModel( id: patientId, namePatient: patientName, nameGuardian: guardianName, deviceId: deviceId, roomId: roomId, ), ); if (deviceId != oldPatient.deviceId || roomId != oldPatient.roomId) { await _updateDeviceAndRoom(oldPatient, deviceId, roomId); } await _ensureRoomExists(roomId, roomName); // PERBAIKAN: Update device_id di users collection jika device berubah if (deviceId != oldPatient.deviceId) { final userDoc = await _firestoreService.getUserByEmail(email); if (userDoc != null) { await _firestoreService.updateUser( uid: userDoc.id, name: guardianName, email: email, deviceId: deviceId, // ✅ UPDATE device_id ); } } Get.back(); AppSnackbar.success('Data berhasil diperbarui'); } catch (e) { AppSnackbar.error('Gagal memperbarui data: $e'); } finally { isLoading.value = false; } } Future _updateDeviceAndRoom( PatientModel oldPatient, String newDeviceId, String newRoomId, ) async { await _firestoreService.deleteDevice(oldPatient.deviceId); await _deleteDeviceFromRealtimeDB(oldPatient.roomId, oldPatient.deviceId); await _createDevice(newDeviceId, newRoomId); await _createDeviceInRealtimeDB(newRoomId, newDeviceId); } // PERBAIKAN LENGKAP: Hapus dari semua collection + Authentication Future deletePatient(String patientId, {String? password}) async { try { isLoading.value = true; final patient = await _firestoreService.getPatientById(patientId); if (patient == null) throw Exception('Pasien tidak ditemukan'); // 1. Hapus dari Realtime Database await _deleteDeviceFromRealtimeDB(patient.roomId, patient.deviceId); // 2. Hapus histories berdasarkan device_id await _firestoreService.deleteHistoriesByDevice(patient.deviceId); // 3. Hapus notifications berdasarkan device_id await _firestoreService.deleteNotificationsByDevice(patient.deviceId); // 4. Hapus schedules berdasarkan device_id await _firestoreService.deleteSchedulesByDevice(patient.deviceId); // 5. Hapus device dari Firestore await _firestoreService.deleteDevice(patient.deviceId); // 6. Cari user berdasarkan guardian name dan device_id final userDoc = await FirebaseFirestore.instance .collection('users') .where('role', isEqualTo: 'guardian') .where('name', isEqualTo: patient.nameGuardian) .where('device_id', isEqualTo: patient.deviceId) .limit(1) .get(); if (userDoc.docs.isNotEmpty) { final userId = userDoc.docs.first.id; final userEmail = userDoc.docs.first.data()['email'] as String; // 7. Hapus dari collection users await _firestoreService.deleteUser(userId); // 8. Hapus dari Firebase Authentication // CATATAN: Memerlukan password untuk delete dari Authentication if (password != null && password.isNotEmpty) { await _firestoreService.deleteUserFromAuth(userEmail, password); } else { // Jika tidak ada password, tampilkan warning print( '⚠️ User tidak terhapus dari Authentication karena password tidak tersedia', ); AppSnackbar.warning( 'User terhapus dari database, tapi tidak dari Authentication. Hubungi admin untuk menghapus akun sepenuhnya.', ); } } // 9. Hapus patient dari Firestore await _firestoreService.deletePatient(patientId); AppSnackbar.success('Pasien berhasil dihapus'); } catch (e) { AppSnackbar.error('Gagal menghapus pasien: $e'); print('❌ Delete patient error: $e'); } finally { isLoading.value = false; } } Future _ensureRoomExists(String roomId, String roomName) async { if (!await _firestoreService.roomExists(roomId)) { await _firestoreService.createRoom( RoomModel( id: roomId, roomName: roomName, capacity: 10, createdAt: DateTime.now(), ), ); } } Future _createDevice(String deviceId, String roomId) async { await _firestoreService.createDevice( DeviceModel( idDevices: deviceId, roomId: roomId, devicesName: 'Infusion Device $deviceId', ), ); } Future _createDeviceInRealtimeDB(String roomId, String deviceId) async { final devicePath = 'realtime/rooms/$roomId/devices/$deviceId'; await FirebaseDatabase.instance.ref().child(devicePath).set({ 'controlling': { 'servo_open': false, 'last_command': DateTime.now().toIso8601String(), }, 'monitoring': { 'device_status': 'connected', 'drop_rate': 0, 'last_update': DateTime.now().toIso8601String(), }, 'settings': {'servo_angle_open': 90, 'servo_angle_close': 0}, }); } Future _deleteDeviceFromRealtimeDB( String roomId, String deviceId, ) async { final devicePath = 'realtime/rooms/$roomId/devices/$deviceId'; await FirebaseDatabase.instance.ref().child(devicePath).remove(); } String _generateRoomId(String roomName) { return roomName .trim() .toLowerCase() .replaceAll(RegExp(r'[^a-z0-9]+'), '_') .replaceAll(RegExp(r'_+'), '_') .replaceAll(RegExp(r'^_|_$'), ''); } }