import 'dart:async';
import 'package:flutter/foundation.dart';
import 'firebase_database_service.dart';
import 'automation_constants.dart';
import 'connection_monitor_service.dart';
import 'notification_service.dart';

/// Service untuk menghandle logika otomatis kontrol waktu dan sensor
/// Berjalan di background untuk monitoring dan eksekusi otomatis
class KontrolAutomationService {
  static final KontrolAutomationService _instance =
      KontrolAutomationService._internal();
  factory KontrolAutomationService() => _instance;
  KontrolAutomationService._internal();

  final FirebaseDatabaseService _dbService = FirebaseDatabaseService();
  final ConnectionMonitorService _connectionMonitor =
      ConnectionMonitorService();

  Timer? _waktuCheckTimer;
  Timer? _sensorCheckTimer;
  StreamSubscription? _sensorSubscription;
  StreamSubscription? _kontrolSubscription;

  bool _isWaktuModeActive = false;
  bool _isSensorModeActive = false;

  // State untuk mencegah trigger berulang
  final Map<String, DateTime> _lastWateringTime = {};
  final Map<String, bool> _isWateringActive = {};

  // ==================== KONTROL WAKTU ====================

  /// Start monitoring waktu mode
  /// Uses NotificationService exact alarm scheduling instead of polling
  /// This eliminates dependency on worker and timer-based checking
  void startWaktuMode() {
    // Disabled on mobile app to let Railway worker handle all scheduling/watering
    debugPrint('🕐 Waktu Mode: Disabled on mobile app (handled by Railway worker instead)');
    if (DateTime.now().year > 2000) return; // Early exit to prevent background scheduling/watering in app

    if (_isWaktuModeActive) return;

    // Start connection monitor for sensor fallback
    _connectionMonitor.start();

    _isWaktuModeActive = true;
    debugPrint('🕐 Waktu Mode: Started (using exact alarm scheduling)');

    // Setup callback to handle watering execution when alarm fires
    NotificationService.setOnWateringScheduleCallback(
      _handleWateringScheduleExecution,
    );

    // Schedule all watering executions using exact alarm
    // This will fire even when app is minimized/killed
    _scheduleWateringExecutions();
  }

  /// Stop monitoring waktu mode
  void stopWaktuMode() {
    _waktuCheckTimer?.cancel();
    _waktuCheckTimer = null;
    _isWaktuModeActive = false;

    // Cancel all watering schedule executions
    _cancelWateringSchedules();

    // Clear callback
    NotificationService.setOnWateringScheduleCallback(null);

    debugPrint('🕐 Waktu Mode: Stopped');
  }

  /// Schedule all watering executions from Firebase
  /// Called when waktu mode starts or when jadwal changes
  Future<void> _scheduleWateringExecutions() async {
    try {
      await NotificationService.instance.scheduleAllWateringExecutions();
      debugPrint(
        '✅ All watering executions scheduled via notification service',
      );
    } catch (e) {
      debugPrint('❌ Error scheduling watering executions: $e');
    }
  }

  /// Cancel all watering schedule executions
  Future<void> _cancelWateringSchedules() async {
    try {
      await NotificationService.instance.cancelAllWateringSchedules();
      debugPrint('✅ All watering schedule executions cancelled');
    } catch (e) {
      debugPrint('❌ Error cancelling watering schedules: $e');
    }
  }

  /// Handle watering execution when scheduled alarm fires
  /// This is called from NotificationService when notification triggers
  Future<void> _handleWateringScheduleExecution(dynamic scheduleData) async {
    try {
      if (scheduleData is! Map) {
        debugPrint('⚠️ Invalid schedule data: $scheduleData');
        return;
      }

      final data = Map<String, dynamic>.from(scheduleData);
      final scheduleId = (data['scheduleId'] ?? 'unknown') as String;
      final pompaAir = data['pompa_air'] ?? true;
      final pompaPupuk = data['pompa_pupuk'] ?? false;
      final durasiDetik = data['durasi'] ?? 60;
      final potAktif = List<int>.from(data['pot_aktif'] ?? []);

      if (potAktif.isNotEmpty) {
        debugPrint(
          '💧 Executing scheduled watering: $scheduleId (${durasiDetik}s)',
        );
        await _executeWatering(
          scheduleId: scheduleId,
          pompaAir: pompaAir,
          pompaPupuk: pompaPupuk,
          pots: potAktif,
          durasiDetik: durasiDetik,
        );
      } else {
        debugPrint('⚠️ No pots selected for $scheduleId');
      }
    } catch (e) {
      debugPrint('❌ Error handling watering execution: $e');
    }
  }

  /// Execute penyiraman dengan durasi tertentu
  Future<void> _executeWatering({
    required String scheduleId,
    required bool pompaAir,
    required bool pompaPupuk,
    required List<int> pots,
    required int durasiDetik,
  }) async {
    try {
      _isWateringActive[scheduleId] = true;
      _lastWateringTime[scheduleId] = DateTime.now();

      // Nyalakan pompa dan valve
      final updates = <String, bool>{};
      if (pompaAir) updates['mosvet_1'] = true;
      if (pompaPupuk) updates['mosvet_2'] = true;

      for (var pot in pots) {
        if (pot >= 1 && pot <= 5) {
          updates['mosvet_${pot + 2}'] = true;
        }
      }

      await _dbService.setMultipleAktuator(updates);
      debugPrint('✅ Watering started: $updates');

      // Tunggu sesuai durasi
      await Future.delayed(Duration(seconds: durasiDetik));

      // Matikan semua
      final offUpdates = <String, bool>{};
      updates.forEach((key, _) => offUpdates[key] = false);
      await _dbService.setMultipleAktuator(offUpdates);

      debugPrint('✅ Watering completed for $scheduleId');

      // Send notification after watering is done
      try {
        final potText =
            pots.length == 5 ? 'semua pot' : 'pot ${pots.join(', ')}';
        await NotificationService.instance.showWateringNotification(
          title: 'IrriGo - Penyiraman Selesai',
          body:
              'Penyiraman selesai untuk $potText selama ${durasiDetik} detik.',
          payload: {
            'type': 'watering_completed',
            'scheduleId': scheduleId,
            'pots': pots,
            'duration': durasiDetik,
          },
        );
      } catch (notifError) {
        debugPrint('⚠️ Error sending notification: $notifError');
      }

      _isWateringActive[scheduleId] = false;
    } catch (e) {
      debugPrint('❌ Error executing watering: $e');
      _isWateringActive[scheduleId] = false;
    }
  }

  // ==================== KONTROL SENSOR ====================

  /// Start monitoring sensor mode
  void startSensorMode() {
    // Disabled on mobile app to let Railway worker handle all automation
    debugPrint('🌡️ Sensor Mode: Disabled on mobile app (handled by Railway worker instead)');
    if (DateTime.now().year > 2000) return; // Early exit to prevent background sensor check in app

    if (_isSensorModeActive) return;

    // Start connection monitor
    _connectionMonitor.start();

    _isSensorModeActive = true;
    debugPrint('🌡️ Sensor Mode: Started');

    // Monitor perubahan sensor lebih responsif (gunakan constant)
    _sensorCheckTimer = Timer.periodic(
      Duration(seconds: AutomationConstants.sensorCheckInterval),
      (timer) => _checkSensorThreshold(),
    );

    // Listen to sensor data real-time
    _sensorSubscription = _dbService.getSensorDataStream().listen((sensorData) {
      if (_isSensorModeActive) {
        _processSensorData(sensorData);
      }
    });

    // Jalankan check pertama kali
    _checkSensorThreshold();
  }

  /// Stop monitoring sensor mode
  void stopSensorMode() {
    _sensorCheckTimer?.cancel();
    _sensorCheckTimer = null;
    _sensorSubscription?.cancel();
    _sensorSubscription = null;
    _isSensorModeActive = false;
    debugPrint('🌡️ Sensor Mode: Stopped');
  }

  /// Check sensor threshold untuk semua pot
  Future<void> _checkSensorThreshold() async {
    try {
      // Check connection first
      if (!_connectionMonitor.isConnected) {
        debugPrint('⚠️ No Firebase connection, skipping sensor check');
        return;
      }

      final kontrolConfig = await _dbService.getKontrolConfig();
      final otomatisEnabled = kontrolConfig['otomatis'] ?? false;

      if (!otomatisEnabled || !_isSensorModeActive) return;

      final batasAtas =
          kontrolConfig['batas_atas'] ?? AutomationConstants.defaultBatasAtas;
      final batasBawah =
          kontrolConfig['batas_bawah'] ?? AutomationConstants.defaultBatasBawah;
      final durasiSensor =
          kontrolConfig['durasi_sensor'] ??
          AutomationConstants.defaultDurasiDetik;
      final modeSensor =
          kontrolConfig['mode_sensor'] ?? AutomationConstants.modeSensorFixed;

      final sensorData = await _dbService.getSensorData();

      // Check setiap pot (soil_1 sampai soil_5)
      debugPrint(
        '🌡️ Checking thresholds: batas_bawah=$batasBawah, batas_atas=$batasAtas, mode=$modeSensor, durasi=${durasiSensor}s',
      );

      for (int i = 1; i <= AutomationConstants.totalPots; i++) {
        final soilKey = 'soil_$i';
        final soilValue = int.tryParse(sensorData[soilKey] ?? '0') ?? 0;

        debugPrint('🌡️ $soilKey = $soilValue (threshold: $batasBawah)');

        // Jika kelembapan di bawah batas bawah, siram pot tersebut
        if (soilValue < batasBawah) {
          debugPrint(
            '⚠️ $soilKey ($soilValue) < batasBawah ($batasBawah) → Triggering watering for POT $i',
          );
          await _waterPotBySensor(
            potNumber: i,
            soilValue: soilValue,
            batasBawah: batasBawah,
            batasAtas: batasAtas,
            durasiSeconds: durasiSensor,
            mode: modeSensor,
          );
        }
      }
    } catch (e) {
      debugPrint('❌ Error checking sensor threshold: $e');
    }
  }

  /// Process sensor data real-time
  void _processSensorData(Map<String, dynamic> sensorData) {
    // Could be used for real-time alerts or logging
    // For now, the periodic check is sufficient
  }

  /// Siram pot berdasarkan sensor
  Future<void> _waterPotBySensor({
    required int potNumber,
    required int soilValue,
    required int batasBawah,
    required int batasAtas,
    required int durasiSeconds,
    required String mode,
  }) async {
    final potKey = 'pot_$potNumber';

    // Prevent multiple watering in short time
    if (_isWateringActive[potKey] == true) return;

    final lastTime = _lastWateringTime[potKey];
    if (lastTime != null) {
      final diff = DateTime.now().difference(lastTime);
      final cooldownSeconds = AutomationConstants.wateringCooldownSeconds;
      if (diff.inSeconds < cooldownSeconds) {
        debugPrint(
          '⏳ POT $potNumber: Cooldown active (${cooldownSeconds - diff.inSeconds}s remaining)',
        );
        return; // Minimum cooldown antar penyiraman
      }
    }

    try {
      _isWateringActive[potKey] = true;
      _lastWateringTime[potKey] = DateTime.now();

      debugPrint(
        '🌡️ Sensor Mode: Watering POT $potNumber (soil: $soilValue < $batasBawah)',
      );
      debugPrint('🔧 Mode: $mode, Durasi: ${durasiSeconds}s');

      // Nyalakan pompa air dan valve pot tersebut
      // pot 1 → mosvet_3, pot 2 → mosvet_4, ... pot 5 → mosvet_7
      debugPrint(
        '💧 Starting watering: POT $potNumber (mosvet_${potNumber + 2})',
      );
      await _dbService.setPompaAir(true);
      await _dbService.setPot(potNumber, true);

      int elapsedSeconds = 0;

      if (mode == 'smart') {
        // SMART MODE: Siram sampai batas atas atau timeout
        debugPrint(
          '🧠 Smart Mode: Target soil_$potNumber >= $batasAtas (currently: $soilValue), max ${durasiSeconds}s',
        );

        while (elapsedSeconds < durasiSeconds && _isSensorModeActive) {
          await Future.delayed(const Duration(seconds: 5));
          elapsedSeconds += 5;

          // Check sensor lagi
          final currentData = await _dbService.getSensorData();
          final currentSoil =
              int.tryParse(currentData['soil_$potNumber'] ?? '0') ?? 0;

          debugPrint(
            '💧 POT $potNumber watering: ${elapsedSeconds}s, soil_$potNumber: $currentSoil',
          );

          if (currentSoil >= batasAtas) {
            debugPrint(
              '✅ POT $potNumber reached target: $currentSoil >= $batasAtas (Smart Mode)',
            );
            break;
          }
        }

        if (elapsedSeconds >= durasiSeconds) {
          debugPrint(
            '⏰ POT $potNumber timeout: ${elapsedSeconds}s (Smart Mode safety)',
          );
        }
      } else {
        // FIXED DURATION MODE: Siram selama durasi tetap
        debugPrint(
          '⏱️ Fixed Duration Mode: Watering for exactly ${durasiSeconds}s',
        );

        while (elapsedSeconds < durasiSeconds && _isSensorModeActive) {
          await Future.delayed(const Duration(seconds: 5));
          elapsedSeconds += 5;

          // Check sensor untuk logging saja (tidak break)
          final currentData = await _dbService.getSensorData();
          final currentSoil =
              int.tryParse(currentData['soil_$potNumber'] ?? '0') ?? 0;

          debugPrint(
            '💧 POT $potNumber watering: ${elapsedSeconds}s/${durasiSeconds}s, soil_$potNumber: $currentSoil',
          );
        }

        debugPrint(
          '✅ POT $potNumber fixed duration completed: ${durasiSeconds}s',
        );
      }

      // Matikan pompa dan valve
      await _dbService.setPompaAir(false);
      await _dbService.setPot(potNumber, false);

      debugPrint(
        '✅ Sensor Mode: Watering completed for POT $potNumber (${elapsedSeconds}s, mode: $mode)',
      );

      // Send notification after watering is done
      try {
        await NotificationService.instance.showWateringNotification(
          title: 'IrriGo - Penyiraman Sensor Selesai',
          body:
              'Penyiraman POT $potNumber selesai (kelembapan: $soilValue%, durasi: ${elapsedSeconds}s, mode: $mode).',
          payload: {
            'type': 'sensor_watering_completed',
            'pot': potNumber,
            'soil': soilValue,
            'duration': elapsedSeconds,
            'mode': mode,
          },
        );
      } catch (notifError) {
        debugPrint('⚠️ Error sending notification: $notifError');
      }

      // Pastikan flag ter-reset dengan benar
      await Future.delayed(const Duration(milliseconds: 500));
      _isWateringActive[potKey] = false;
    } catch (e) {
      debugPrint('❌ Error watering pot by sensor: $e');

      // Matikan semua untuk safety
      try {
        await _dbService.setPompaAir(false);
        await _dbService.setPot(potNumber, false);
      } catch (cleanupError) {
        debugPrint('❌ Error during cleanup: $cleanupError');
      }

      // Reset flag
      _isWateringActive[potKey] = false;
    }
  }

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

  /// Get status semua automation
  Map<String, bool> getAutomationStatus() {
    return {'waktuMode': _isWaktuModeActive, 'sensorMode': _isSensorModeActive};
  }

  /// Stop semua automation
  void stopAll() {
    stopWaktuMode();
    stopSensorMode();
    debugPrint('⏹️ All automation stopped');
  }

  /// Cleanup saat app dispose
  void dispose() {
    stopAll();
    _kontrolSubscription?.cancel();
  }
}
