import 'package:flutter/foundation.dart'; import '../models/message.dart'; import '../models/sar_marker.dart'; import '../services/message_storage_service.dart'; import '../utils/sar_message_parser.dart'; /// Messages Provider - manages message history and SAR markers class MessagesProvider with ChangeNotifier { final List _messages = []; final Map _sarMarkers = {}; final MessageStorageService _storageService = MessageStorageService(); bool _isInitialized = false; List get messages => List.unmodifiable(_messages); List get contactMessages => _messages.where((m) => m.isContactMessage).toList(); List get channelMessages => _messages.where((m) => m.isChannelMessage).toList(); List get sarMarkerMessages => _messages.where((m) => m.isSarMarker).toList(); List get sarMarkers => _sarMarkers.values.toList(); List get foundPersonMarkers => sarMarkers.where((m) => m.type == SarMarkerType.foundPerson).toList(); List get fireMarkers => sarMarkers.where((m) => m.type == SarMarkerType.fire).toList(); List get stagingAreaMarkers => sarMarkers.where((m) => m.type == SarMarkerType.stagingArea).toList(); List get objectMarkers => sarMarkers.where((m) => m.type == SarMarkerType.object).toList(); bool get isInitialized => _isInitialized; /// Initialize and load persisted messages Future initialize() async { if (_isInitialized) return; try { print('📦 [MessagesProvider] Loading persisted messages...'); final storedMessages = await _storageService.loadMessages(); // Add stored messages with enhancement to ensure SAR detection for (final message in storedMessages) { // Re-enhance each message to ensure SAR markers are properly detected // This handles cases where messages were stored before enhancement logic final enhancedMessage = SarMessageParser.enhanceMessage(message); _messages.add(enhancedMessage); // Extract SAR markers if (enhancedMessage.isSarMarker) { final marker = enhancedMessage.toSarMarker(); if (marker != null) { _sarMarkers[marker.id] = marker; } } } _isInitialized = true; print('✅ [MessagesProvider] Loaded ${storedMessages.length} persisted messages'); notifyListeners(); } catch (e) { print('❌ [MessagesProvider] Error initializing: $e'); _isInitialized = true; // Mark as initialized even on error } } /// Add a message void addMessage(Message message) { // Always enhance message with SAR parser to detect SAR markers final enhancedMessage = SarMessageParser.enhanceMessage(message); // Debug: Check if message is SAR if (message.text.startsWith('S:')) { print('🔍 [MessagesProvider] Processing SAR message: ${message.text}'); print(' isSarMarker: ${enhancedMessage.isSarMarker}'); print(' sarMarkerType: ${enhancedMessage.sarMarkerType}'); } _messages.add(enhancedMessage); // If it's a SAR marker message, extract and store the marker if (enhancedMessage.isSarMarker) { final marker = enhancedMessage.toSarMarker(); if (marker != null) { _sarMarkers[marker.id] = marker; } } // Persist to storage asynchronously _persistMessages(); notifyListeners(); } /// Add multiple messages void addMessages(List messages) { for (final message in messages) { // Always enhance message with SAR parser to detect SAR markers final enhancedMessage = SarMessageParser.enhanceMessage(message); _messages.add(enhancedMessage); if (enhancedMessage.isSarMarker) { final marker = enhancedMessage.toSarMarker(); if (marker != null) { _sarMarkers[marker.id] = marker; } } } // Persist to storage asynchronously _persistMessages(); notifyListeners(); } /// Persist messages to storage (async, non-blocking) Future _persistMessages() async { try { await _storageService.saveMessages(_messages); } catch (e) { print('❌ [MessagesProvider] Error persisting messages: $e'); } } /// Get messages for a specific contact List getMessagesForContact(String senderKeyShort) { return _messages .where((m) => m.isContactMessage && m.senderKeyShort != null && m.senderKeyShort!.startsWith(senderKeyShort)) .toList(); } /// Get messages for a specific channel List getMessagesForChannel(int channelIdx) { return _messages .where((m) => m.isChannelMessage && m.channelIdx == channelIdx) .toList(); } /// Get recent messages (last N messages) List getRecentMessages({int count = 50}) { final sorted = List.from(_messages) ..sort((a, b) => b.sentAt.compareTo(a.sentAt)); return sorted.take(count).toList(); } /// Get messages from last N hours List getMessagesSince(Duration duration) { final cutoff = DateTime.now().subtract(duration); return _messages.where((m) => m.sentAt.isAfter(cutoff)).toList(); } /// Search messages by text List searchMessages(String query) { if (query.isEmpty) return []; final lowerQuery = query.toLowerCase(); return _messages .where((m) => m.text.toLowerCase().contains(lowerQuery)) .toList(); } /// Get SAR marker by ID SarMarker? getSarMarker(String id) { return _sarMarkers[id]; } /// Get recent SAR markers (within last hour) List getRecentSarMarkers() { return sarMarkers.where((m) => m.isRecent).toList(); } /// Remove a SAR marker void removeSarMarker(String id) { _sarMarkers.remove(id); notifyListeners(); } /// Clear all messages void clearMessages() { _messages.clear(); _persistMessages(); notifyListeners(); } /// Clear all SAR markers void clearSarMarkers() { _sarMarkers.clear(); notifyListeners(); } /// Clear all data void clearAll() { _messages.clear(); _sarMarkers.clear(); _persistMessages(); notifyListeners(); } /// Get storage statistics Future> getStorageStats() async { return await _storageService.getStorageStats(); } /// Get message statistics Map get messageStats { return { 'total': _messages.length, 'contact': contactMessages.length, 'channel': channelMessages.length, 'sar': sarMarkerMessages.length, 'sarMarkers': sarMarkers.length, }; } /// Get SAR marker statistics Map get sarMarkerStats { return { 'total': sarMarkers.length, 'foundPerson': foundPersonMarkers.length, 'fire': fireMarkers.length, 'stagingArea': stagingAreaMarkers.length, 'object': objectMarkers.length, }; } }