import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'dart:async';
import '../../../services/firestore_service.dart';
import '../../../services/realtime_database_service.dart';
import '../../../services/notification_service.dart';
import '../../../models/patient_model.dart';
import '../../../models/room_model.dart';
import '../../../models/realtime_monitoring_model.dart';
import '../../../widgets/app_snackbar.dart';

class InfusMonitoring {
  final String id;
  final String patientName;
  final String deviceId;
  final String room;
  final String roomId;
  final String dropsPerMinute;
  final DateTime lastUpdate;
  final String deviceStatus;

  InfusMonitoring({
    required this.id,
    required this.patientName,
    required this.deviceId,
    required this.room,
    required this.roomId,
    required this.dropsPerMinute,
    required this.lastUpdate,
    required this.deviceStatus,
  });
}

class HomeController extends GetxController {
  final searchController = TextEditingController();
  final FirestoreService _firestoreService = FirestoreService();
  final RealtimeDatabaseService _realtimeService = RealtimeDatabaseService();
  final NotificationService _notificationService = NotificationService();

  final currentCarouselIndex = 0.obs;
  final bannerImages = [
    'assets/images/banner-slider1.png',
    'assets/images/banner-slider2.png',
  ];

  final monitoringList = <InfusMonitoring>[].obs;
  final isLoading = true.obs;

  List<RoomModel> _cachedRooms = [];

  StreamSubscription? _patientsSubscription;
  StreamSubscription? _roomsSubscription;

  // Map deviceId -> StreamSubscription untuk per-device realtime stream
  final Map<String, StreamSubscription> _deviceSubscriptions = {};

  // Map deviceId -> data realtime terbaru
  final Map<String, RealtimeMonitoringModel> _realtimeDataMap = {};

  List<PatientModel> _latestPatients = [];

  bool _patientsReady = false;

  final Set<String> _alertedDevices = {};

  @override
  void onInit() {
    super.onInit();
    _initializeNotificationService();
    _initializeMonitoring();
  }

  @override
  void onClose() {
    searchController.dispose();
    _patientsSubscription?.cancel();
    _roomsSubscription?.cancel();
    // Cancel semua per-device subscriptions
    for (final sub in _deviceSubscriptions.values) {
      sub.cancel();
    }
    _deviceSubscriptions.clear();
    super.onClose();
  }

  Future<void> _initializeNotificationService() async {
    try {
      await _notificationService.initialize();
    } catch (e) {
      print('Error initializing notification service: $e');
    }
  }

  void _initializeMonitoring() {
    isLoading.value = true;
    _patientsReady = false;

    // 1. Cache rooms
    _roomsSubscription = _firestoreService.getRoomsStream().listen((rooms) {
      _cachedRooms = rooms;
    });

    // 2. Patients stream
    _patientsSubscription = _firestoreService.getPatientsStream().listen(
      (patients) {
        _latestPatients = patients;
        _patientsReady = true;
        _syncDeviceSubscriptions(patients);
      },
      onError: (error) {
        print('Error patients stream: $error');
        isLoading.value = false;
        AppSnackbar.error('Gagal memuat data pasien');
      },
    );

    // Timeout fallback
    Future.delayed(const Duration(seconds: 8), () {
      if (isLoading.value) {
        print('Timeout: force stop loading');
        isLoading.value = false;
      }
    });
  }

  /// Sinkronisasi per-device stream — ikuti pola HomePatientController
  /// pakai getDeviceStream(dbRoomId, deviceId) bukan getAllDevicesStream()
  void _syncDeviceSubscriptions(List<PatientModel> patients) {
    final currentDeviceIds = patients.map((p) => p.deviceId).toSet();
    final existingDeviceIds = _deviceSubscriptions.keys.toSet();

    // Cancel stream untuk device yang sudah tidak ada di patients
    final removedIds = existingDeviceIds.difference(currentDeviceIds);
    for (final deviceId in removedIds) {
      _deviceSubscriptions[deviceId]?.cancel();
      _deviceSubscriptions.remove(deviceId);
      _realtimeDataMap.remove(deviceId);
    }

    // Tambah stream untuk device baru
    final newIds = currentDeviceIds.difference(existingDeviceIds);
    for (final patient in patients.where((p) => newIds.contains(p.deviceId))) {
      _subscribeToDevice(patient);
    }
  }

  void _subscribeToDevice(PatientModel patient) {
    // Format room ID sama persis seperti HomePatientController
    final dbRoomId = patient.roomId.toLowerCase().replaceAll(' ', '_');
    final deviceId = patient.deviceId;

    print('Subscribing to device: $deviceId in room: $dbRoomId');

    final sub = _realtimeService
        .getDeviceStream(dbRoomId, deviceId)
        .listen(
          (device) {
            if (device != null) {
              _realtimeDataMap[deviceId] = device;
            } else {
              // Device null = disconnected, hapus dari map
              _realtimeDataMap.remove(deviceId);
            }
            // Rebuild setiap ada update dari device manapun
            if (_patientsReady) {
              _rebuildMonitoringList();
            }
          },
          onError: (error) {
            print('Error stream device $deviceId: $error');
            // Tetap rebuild walau error, device akan tampil sebagai disconnected
            if (_patientsReady) {
              _rebuildMonitoringList();
            }
          },
          cancelOnError: false,
        );

    _deviceSubscriptions[deviceId] = sub;
  }

  void _rebuildMonitoringList() {
    final List<InfusMonitoring> combinedData = [];

    for (var patient in _latestPatients) {
      final realtimeDevice = _realtimeDataMap[patient.deviceId];
      final roomName = _getRoomNameFromCache(patient.roomId);
      final dropRate = realtimeDevice?.dropRate ?? 0.0;
      final lastUpdate = realtimeDevice?.lastUpdate ?? DateTime.now();
      final deviceStatus = realtimeDevice?.deviceStatus ?? 'disconnected';

      _checkDropRate(
        patient: patient,
        dropRate: dropRate,
        roomName: roomName,
        deviceStatus: deviceStatus,
      );

      combinedData.add(
        InfusMonitoring(
          id: patient.id,
          patientName: patient.namePatient,
          deviceId: patient.deviceId,
          room: roomName,
          roomId: patient.roomId,
          dropsPerMinute: '${dropRate.toStringAsFixed(0)} tpm',
          lastUpdate: lastUpdate,
          deviceStatus: deviceStatus,
        ),
      );
    }

    monitoringList.value = combinedData;
    isLoading.value = false;
  }

  String _getRoomNameFromCache(String roomId) {
    final room = _cachedRooms.firstWhereOrNull(
      (r) => r.id == roomId || r.roomName.toLowerCase() == roomId.toLowerCase(),
    );
    return room?.roomName ?? roomId;
  }

  Future<void> _checkDropRate({
    required PatientModel patient,
    required double dropRate,
    required String roomName,
    required String deviceStatus,
  }) async {
    final deviceId = patient.deviceId;

    if (dropRate == 0.0 && deviceStatus == 'connected') {
      if (!_alertedDevices.contains(deviceId)) {
        await _notificationService.showDropRateAlert(
          patientId: patient.id,
          patientName: patient.namePatient,
          deviceId: deviceId,
          roomName: roomName,
        );
        _alertedDevices.add(deviceId);
      }
    } else if (dropRate > 0.0) {
      if (_alertedDevices.contains(deviceId)) {
        _alertedDevices.remove(deviceId);
        _notificationService.clearCooldown(deviceId);
        await _notificationService.cancelNotificationByDeviceId(deviceId);
      }
    }
  }

  Future<void> controlInfusServo(
    String deviceId,
    String roomId,
    bool open,
  ) async {
    try {
      final dbRoomId = roomId.toLowerCase().replaceAll(' ', '_');
      await _realtimeService.controlServo(dbRoomId, deviceId, open);
      AppSnackbar.success(open ? 'Infus dibuka' : 'Infus ditutup');
    } catch (e) {
      AppSnackbar.error('Gagal mengontrol infus');
    }
  }

  void updateCarouselIndex(int index) {
    currentCarouselIndex.value = index;
  }

  void showLogoutDialog(BuildContext context) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          backgroundColor: Colors.white,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(15),
          ),
          title: const Text(
            'Konfirmasi Logout',
            style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
          ),
          content: const Text(
            'Yakin ingin keluar?',
            style: TextStyle(fontSize: 16),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              style: TextButton.styleFrom(
                foregroundColor: Colors.grey[600],
                padding: const EdgeInsets.symmetric(
                  vertical: 12,
                  horizontal: 20,
                ),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
              ),
              child: const Text('Batal'),
            ),
            ElevatedButton(
              onPressed: () async {
                Navigator.of(context).pop();
                await FirebaseAuth.instance.signOut();
                Get.offAllNamed('/login');
              },
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.red,
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(
                  vertical: 12,
                  horizontal: 20,
                ),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
              ),
              child: const Text(
                'Logout',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
          ],
        );
      },
    );
  }

  String getLastUpdateText(DateTime lastUpdate) {
    final difference = DateTime.now().difference(lastUpdate);
    if (difference.inMinutes < 1) {
      return 'Just now';
    } else if (difference.inMinutes < 60) {
      return '${difference.inMinutes}m ago';
    } else if (difference.inHours < 24) {
      return '${difference.inHours}h ago';
    } else {
      return '${difference.inDays}d ago';
    }
  }

  void clearDeviceAlert(String deviceId) {
    _alertedDevices.remove(deviceId);
    _notificationService.clearCooldown(deviceId);
  }

  void clearAllAlerts() {
    _alertedDevices.clear();
    _notificationService.clearAllCooldowns();
  }
}
