import 'dart:async'; import 'package:flutter/material.dart'; import 'package:firebase_database/firebase_database.dart'; import '../models/history_model.dart'; import '../models/control_history_model.dart'; import '../services/firebase_service.dart'; class HistoryProvider extends ChangeNotifier { List monitoringHistory = []; List controlHistory = []; bool isLoading = false; StreamSubscription? monitoringSubscription; StreamSubscription? _manualSubscription; StreamSubscription? _autoSubscription; final List _manualHistory = []; final List _autoHistory = []; // ================= MONITORING ================= void startMonitoringListener() { monitoringSubscription?.cancel(); monitoringSubscription = FirebaseService.monitoringHistoryRef.onValue .listen((event) { monitoringHistory.clear(); if (event.snapshot.value == null) { notifyListeners(); return; } final data = Map.from(event.snapshot.value as Map); data.forEach((key, value) { monitoringHistory.add( HistoryModel.fromMap(Map.from(value)), ); }); monitoringHistory.sort((a, b) => b.timestamp.compareTo(a.timestamp)); notifyListeners(); }); } // ================= CONTROL (Manual & Auto triggers combined) ================= void startControlListener() { _manualSubscription?.cancel(); _autoSubscription?.cancel(); // 1. Listen to manual controls _manualSubscription = FirebaseService.controlHistoryRef.onValue.listen((event) { _manualHistory.clear(); if (event.snapshot.value != null) { final data = Map.from(event.snapshot.value as Map); data.forEach((key, value) { _manualHistory.add( ControlHistoryModel.fromMap(Map.from(value)), ); }); } _combineAndSortHistory(); }); // 2. Listen to auto triggers _autoSubscription = FirebaseService.acAutoTriggerHistoryRef.onValue.listen((event) { _autoHistory.clear(); if (event.snapshot.value != null) { final data = Map.from(event.snapshot.value as Map); data.forEach((key, value) { final mapVal = Map.from(value); final rawAction = mapVal['action']?.toString() ?? 'unknown'; String actionText = rawAction; if (rawAction == 'auto_off') { actionText = 'AC Dimatikan Otomatis (Semua Parameter Baik)'; } else if (rawAction == 'auto_dry') { actionText = 'Mode Dry Otomatis (Kelembapan Tinggi)'; } else if (rawAction == 'auto_cool') { actionText = 'Mode Cool Otomatis (Suhu/Kelembapan Luar Batas)'; } else if (rawAction == 'auto_fan') { actionText = 'Mode Fan Otomatis (Udara Buruk)'; } final ts = mapVal['timestamp'] is int ? mapVal['timestamp'] : 0; _autoHistory.add( ControlHistoryModel( action: actionText, source: 'Auto (ESP32)', timestamp: _parseTimestampString(ts), rawTimestamp: ts, ), ); }); } _combineAndSortHistory(); }); } void _combineAndSortHistory() { controlHistory = [..._manualHistory, ..._autoHistory]; controlHistory.sort((a, b) => b.rawTimestamp.compareTo(a.rawTimestamp)); notifyListeners(); } String _parseTimestampString(int value) { if (value == 0) return ''; final dt = DateTime.fromMillisecondsSinceEpoch(value * 1000); return "${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')} " "${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}:${dt.second.toString().padLeft(2, '0')}"; } // ================= CLEAR HISTORIES ================= Future clearMonitoringHistory() async { try { isLoading = true; notifyListeners(); await FirebaseService.monitoringHistoryRef.remove(); monitoringHistory.clear(); isLoading = false; notifyListeners(); } catch (e) { isLoading = false; notifyListeners(); rethrow; } } Future clearControlHistory() async { try { isLoading = true; notifyListeners(); await FirebaseService.controlHistoryRef.remove(); await FirebaseService.acAutoTriggerHistoryRef.remove(); _manualHistory.clear(); _autoHistory.clear(); controlHistory.clear(); isLoading = false; notifyListeners(); } catch (e) { isLoading = false; notifyListeners(); rethrow; } } @override void dispose() { monitoringSubscription?.cancel(); _manualSubscription?.cancel(); _autoSubscription?.cancel(); super.dispose(); } }