import 'package:firebase_database/firebase_database.dart';
import '../models/realtime_monitoring_model.dart';

class RealtimeDatabaseService {
  final DatabaseReference _database = FirebaseDatabase.instance.ref();

  // ==================== MONITORING ====================

  Stream<Map<String, RealtimeMonitoringModel>> getRoomDevicesStream(
    String roomId,
  ) {
    return _database
        .child('realtime/rooms/$roomId/devices')
        .onValue
        .map((event) {
      final Map<String, RealtimeMonitoringModel> devices = {};

      if (event.snapshot.value != null) {
        final data = event.snapshot.value as Map<dynamic, dynamic>;
        data.forEach((deviceId, deviceData) {
          if (deviceData is Map) {
            devices[deviceId] = RealtimeMonitoringModel.fromRealtimeDB(
              deviceId,
              roomId,
              deviceData as Map<dynamic, dynamic>,
            );
          }
        });
      }

      return devices;
    });
  }

  Stream<RealtimeMonitoringModel?> getDeviceStream(
    String roomId,
    String deviceId,
  ) {
    return _database
        .child('realtime/rooms/$roomId/devices/$deviceId')
        .onValue
        .map((event) {
      if (event.snapshot.value != null) {
        final data = event.snapshot.value as Map<dynamic, dynamic>;
        return RealtimeMonitoringModel.fromRealtimeDB(deviceId, roomId, data);
      }
      return null;
    });
  }

  Stream<List<RealtimeMonitoringModel>> getAllDevicesStream() {
    return _database.child('realtime/rooms').onValue.map((event) {
      final List<RealtimeMonitoringModel> allDevices = [];

      if (event.snapshot.value != null) {
        final rooms = event.snapshot.value as Map<dynamic, dynamic>;

        rooms.forEach((roomId, roomData) {
          if (roomData is Map && roomData['devices'] != null) {
            final devices = roomData['devices'] as Map<dynamic, dynamic>;

            devices.forEach((deviceId, deviceData) {
              if (deviceData is Map) {
                allDevices.add(
                  RealtimeMonitoringModel.fromRealtimeDB(
                    deviceId,
                    roomId,
                    deviceData as Map<dynamic, dynamic>,
                  ),
                );
              }
            });
          }
        });
      }

      return allDevices;
    });
  }

  Future<RealtimeMonitoringModel?> getDevice(
    String roomId,
    String deviceId,
  ) async {
    try {
      final snapshot =
          await _database.child('realtime/rooms/$roomId/devices/$deviceId').get();

      if (snapshot.value != null) {
        final data = snapshot.value as Map<dynamic, dynamic>;
        return RealtimeMonitoringModel.fromRealtimeDB(deviceId, roomId, data);
      }
      return null;
    } catch (e) {
      return null;
    }
  }

  // ==================== CONTROL ====================

  Future<void> controlServo(String roomId, String deviceId, bool open) async {
    await _database
        .child('realtime/rooms/$roomId/devices/$deviceId/controlling')
        .update({
      'servo_open': open,
      'last_command': DateTime.now().toIso8601String(),
    });
  }

  Future<void> updateDropRate(
    String roomId,
    String deviceId,
    double dropRate,
  ) async {
    await _database
        .child('realtime/rooms/$roomId/devices/$deviceId/monitoring')
        .update({
      'drop_rate': dropRate,
      'last_update': DateTime.now().toIso8601String(),
    });
  }

  Future<void> updateDeviceStatus(
    String roomId,
    String deviceId,
    String status,
  ) async {
    await _database
        .child('realtime/rooms/$roomId/devices/$deviceId/monitoring')
        .update({
      'device_status': status,
      'last_update': DateTime.now().toIso8601String(),
    });
  }

  Future<void> updateServoSettings(
    String roomId,
    String deviceId,
    int angleOpen,
    int angleClose,
  ) async {
    await _database
        .child('realtime/rooms/$roomId/devices/$deviceId/settings')
        .update({
      'servo_angle_open': angleOpen,
      'servo_angle_close': angleClose,
    });
  }

  // ==================== UTILITY ====================

  Future<bool> isDeviceConnected(String roomId, String deviceId) async {
    try {
      final device = await getDevice(roomId, deviceId);
      return device?.deviceStatus == 'connected';
    } catch (e) {
      return false;
    }
  }

  Future<double> getDeviceDropRate(String roomId, String deviceId) async {
    try {
      final snapshot = await _database
          .child(
              'realtime/rooms/$roomId/devices/$deviceId/monitoring/drop_rate')
          .get();

      if (snapshot.value != null) {
        return (snapshot.value as num).toDouble();
      }
      return 0.0;
    } catch (e) {
      return 0.0;
    }
  }
}