import 'dart:async'; import 'package:flutter/foundation.dart'; import '../models/price_data.dart'; import '../services/websocket_service.dart'; import '../services/api_service.dart'; import '../services/storage_service.dart'; import '../services/notification_service.dart'; class PriceProvider with ChangeNotifier { final WebSocketService _wsService = WebSocketService(); final ApiService _apiService = ApiService(); final StorageService _storageService = StorageService(); final NotificationService _notificationService = NotificationService(); LatestPrice? _latestPrice; HistoryData? _historyData; String _connectionStatus = 'Disconnected'; List _alerts = []; double? _customAuecAmount; String _selectedRange = '7d'; bool _isLoading = false; bool _isHistoryLoading = false; LatestPrice? get latestPrice => _latestPrice; HistoryData? get historyData => _historyData; String get connectionStatus => _connectionStatus; List get alerts => _alerts; double? get customAuecAmount => _customAuecAmount; String get selectedRange => _selectedRange; bool get isLoading => _isLoading; bool get isHistoryLoading => _isHistoryLoading; PriceProvider() { _initialize(); } Timer? _pollTimer; void _initialize() { // Load saved data _loadAlerts(); _loadCustomAuecAmount(); // Connect WebSocket (currently disabled) _wsService.connect(); // Listen to WebSocket streams _wsService.latestPriceStream.listen((price) { _latestPrice = price; _checkAlerts(price); notifyListeners(); }); _wsService.connectionStatusStream.listen((status) { _connectionStatus = status; notifyListeners(); }); // Fetch initial data fetchInitialData(); // Start polling for updates every 5 minutes as backup to WebSocket _startPolling(); } void _startPolling() { _pollTimer = Timer.periodic(const Duration(minutes: 5), (timer) { fetchInitialData(); }); } Future fetchInitialData() async { final latest = await _apiService.fetchLatestPrice(); if (latest != null) { _latestPrice = latest; notifyListeners(); } await fetchHistory(_selectedRange); } Future fetchHistory(String range) async { _isHistoryLoading = true; _selectedRange = range; notifyListeners(); try { final history = await _apiService.fetchHistory(range); if (history != null) { _historyData = history; } _wsService.requestHistory(range); } catch (e) { if (kDebugMode) { print('Error fetching history: $e'); } } finally { _isHistoryLoading = false; notifyListeners(); } } Future _loadAlerts() async { _alerts = await _storageService.getAlerts(); notifyListeners(); } Future _loadCustomAuecAmount() async { _customAuecAmount = await _storageService.getCustomAuecAmount(); notifyListeners(); } Future addAlert(double auecAmount, double maxPrice) async { final alert = PriceAlert( id: DateTime.now().millisecondsSinceEpoch.toString(), auecAmount: auecAmount, maxPrice: maxPrice, enabled: true, ); await _storageService.addAlert(alert); await _loadAlerts(); } Future toggleAlert(String id) async { final alert = _alerts.firstWhere((a) => a.id == id); final updated = alert.copyWith(enabled: !alert.enabled); await _storageService.updateAlert(updated); await _loadAlerts(); } Future deleteAlert(String id) async { await _storageService.deleteAlert(id); await _loadAlerts(); } Future setCustomAuecAmount(double amount) async { await _storageService.setCustomAuecAmount(amount); _customAuecAmount = amount; notifyListeners(); } void _checkAlerts(LatestPrice price) { for (final alert in _alerts) { if (!alert.enabled) continue; final matchingSeller = price.allPrices.firstWhere( (p) { final totalPrice = (alert.auecAmount / 1000000) * p.pricePerMillion; return totalPrice <= alert.maxPrice; }, orElse: () => price.allPrices.first, ); final totalPrice = (alert.auecAmount / 1000000) * matchingSeller.pricePerMillion; if (totalPrice <= alert.maxPrice) { // Trigger notification _notificationService.showPriceAlert( title: 'Price Alert Triggered!', body: '${(alert.auecAmount / 1000000000).toStringAsFixed(1)}B AUEC available for \$${totalPrice.toStringAsFixed(2)} from ${matchingSeller.sellerName}', auecAmount: alert.auecAmount, price: totalPrice, seller: matchingSeller.sellerName, ); // Disable alert toggleAlert(alert.id); } } } @override void dispose() { _pollTimer?.cancel(); _wsService.dispose(); super.dispose(); } }