// lib/services/user_preferences_service.dart import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:environment_monitoring_app/services/api_service.dart'; // Contains DatabaseHelper import 'package:environment_monitoring_app/services/database_helper.dart'; /// A dedicated service to manage the user's local preferences for /// module-specific submission destinations. class UserPreferencesService { final DatabaseHelper _dbHelper = DatabaseHelper(); static const _defaultPrefsSavedKey = 'default_preferences_saved'; // Moved from settings.dart for central access // This list now includes all your modules final List> _configurableModules = [ {'key': 'marine_tarball', 'name': 'Marine Tarball'}, {'key': 'marine_in_situ', 'name': 'Marine In-Situ'}, {'key': 'marine_investigative', 'name': 'Marine Investigative'}, {'key': 'river_in_situ', 'name': 'River In-Situ'}, {'key': 'river_triennial', 'name': 'River Triennial'}, {'key': 'river_investigative', 'name': 'River Investigative'}, {'key': 'air_installation', 'name': 'Air Installation'}, {'key': 'air_collection', 'name': 'Air Collection'}, ]; /// Checks if default preferences have been set. If not, it applies /// and saves the default submission destinations for all modules. /// This ensures the app is ready for submissions immediately after the first login. Future applyAndSaveDefaultPreferencesIfNeeded() async { final prefs = await SharedPreferences.getInstance(); if (prefs.getBool(_defaultPrefsSavedKey) ?? false) { // Defaults have already been saved for this session, do nothing. return; } debugPrint("Applying and auto-saving default submission preferences for the first time."); try { // Get all possible configs from the database just once final allApiConfigs = await _dbHelper.loadApiConfigs() ?? []; final allFtpConfigs = await _dbHelper.loadFtpConfigs() ?? []; for (var module in _configurableModules) { final moduleKey = module['key']!; // 1. Save master switches to enable API and FTP for the module. await saveModulePreference( moduleName: moduleKey, isApiEnabled: true, isFtpEnabled: true, ); // 2. Determine default API links // This is correct: Tick any API server marked as 'is_active' by default. final defaultApiLinks = allApiConfigs.map((config) { bool isEnabled = (config['is_active'] == 1 || config['is_active'] == true); return {...config, 'is_enabled': isEnabled}; }).toList(); // 3. Determine default FTP links // Handle mapping 'marine_in_situ' -> 'marine_manual' String expectedFtpModuleKey = moduleKey; if (moduleKey == 'marine_in_situ') { expectedFtpModuleKey = 'marine_manual'; } else if (moduleKey == 'river_in_situ') { expectedFtpModuleKey = 'river_manual'; } final defaultFtpLinks = allFtpConfigs.map((config) { final String configModule = config['ftp_module'] ?? ''; final bool isActive = (config['is_active'] == 1 || config['is_active'] == true); // Enable if the config's module matches the current moduleKey AND it's active bool isEnabled = (configModule == expectedFtpModuleKey) && isActive; return {...config, 'is_enabled': isEnabled}; }).toList(); // --- END MODIFICATION --- // 4. Save the default links to the database. await saveApiLinksForModule(moduleKey, defaultApiLinks); await saveFtpLinksForModule(moduleKey, defaultFtpLinks); } // 5. Set the flag to prevent this from running again until next login. await prefs.setBool(_defaultPrefsSavedKey, true); debugPrint("Default submission preferences have been auto-saved."); } catch (e) { debugPrint("Error auto-saving default preferences: $e"); } } /// Retrieves a module's master submission preferences. /// This method now returns null if no preference is found. Future?> getModulePreference(String moduleName) async { final preference = await _dbHelper.getModulePreference(moduleName); if (preference != null) { return preference; } return null; } /// Saves or updates a module's master on/off switches for API and FTP submissions. Future saveModulePreference({ required String moduleName, required bool isApiEnabled, required bool isFtpEnabled, }) async { await _dbHelper.saveModulePreference( moduleName: moduleName, isApiEnabled: isApiEnabled, isFtpEnabled: isFtpEnabled, ); } /// Retrieves all available API configurations and merges them with the user's /// saved preferences for a specific module. /// /// This is primarily for the Settings UI to display all possible destinations /// with their current enabled/disabled state (e.g., checkboxes). Future>> getAllApiConfigsWithModulePreferences(String moduleName) async { // 1. Get all possible API destinations that have been synced to the device. final allApiConfigs = await _dbHelper.loadApiConfigs() ?? []; if (allApiConfigs.isEmpty) return []; // 2. Get the specific links the user has previously saved for this module. final savedLinks = await _dbHelper.getAllApiLinksForModule(moduleName); // 3. Merge the two lists. return allApiConfigs.map((config) { final configId = config['api_config_id']; bool isEnabled; // --- START MODIFICATION: Corrected Merge Logic --- Map? matchingLink; try { matchingLink = savedLinks.firstWhere( (link) => link['api_config_id'] == configId, ); } catch (e) { matchingLink = null; // No match found } if (matchingLink != null) { // A preference exists. Use the saved value. isEnabled = matchingLink['is_enabled'] as bool? ?? false; } else { // No preference saved for this config. Apply default logic. // (This handles newly synced configs automatically) isEnabled = (config['is_active'] == 1 || config['is_active'] == true); } // --- END MODIFICATION --- // Return a new map containing the original config details plus the 'is_enabled' flag. return { ...config, 'is_enabled': isEnabled, }; }).toList(); } /// Retrieves all available FTP configurations and merges them with the user's /// saved preferences for a specific module. (For the Settings UI). Future>> getAllFtpConfigsWithModulePreferences(String moduleName) async { final allFtpConfigs = await _dbHelper.loadFtpConfigs() ?? []; if (allFtpConfigs.isEmpty) return []; final savedLinks = await _dbHelper.getAllFtpLinksForModule(moduleName); // Handle mapping 'marine_in_situ' -> 'marine_manual' String expectedFtpModuleKey = moduleName; if (moduleName == 'marine_in_situ') { expectedFtpModuleKey = 'marine_manual'; } else if (moduleName == 'river_in_situ') { expectedFtpModuleKey = 'river_manual'; } return allFtpConfigs.map((config) { final configId = config['ftp_config_id']; bool isEnabled; // --- START MODIFICATION: Corrected Merge Logic --- Map? matchingLink; try { matchingLink = savedLinks.firstWhere( (link) => link['ftp_config_id'] == configId, ); } catch (e) { matchingLink = null; // No match found } if (matchingLink != null) { // A preference exists. Use the saved value. isEnabled = matchingLink['is_enabled'] as bool? ?? false; } else { // No preference saved for this config. Apply default logic. final String configModule = config['ftp_module'] ?? ''; final bool isActive = (config['is_active'] == 1 || config['is_active'] == true); // Use the mapped key for comparison isEnabled = (configModule == expectedFtpModuleKey) && isActive; } // --- END MODIFICATION --- return { ...config, 'is_enabled': isEnabled, }; }).toList(); } /// Saves the complete set of enabled/disabled API links for a specific module. /// This will replace all previous links for that module. Future saveApiLinksForModule(String moduleName, List> links) async { await _dbHelper.saveApiLinksForModule(moduleName, links); } /// Saves the complete set of enabled/disabled FTP links for a specific module. Future saveFtpLinksForModule(String moduleName, List> links) async { await _dbHelper.saveFtpLinksForModule(moduleName, links); } /// Retrieves only the API configurations that are actively enabled for a given module. /// /// This is primarily for the submission services to know exactly which /// destinations to send data to. Future>> getEnabledApiConfigsForModule(String moduleName) async { // 1. Check the master switch for the module. final pref = await _dbHelper.getModulePreference(moduleName); // Use direct DB call if (pref == null || !(pref['is_api_enabled'] as bool)) { debugPrint("API submissions are disabled for module '$moduleName'."); return []; // Return empty list if API is disabled or not set. } // 2. Get all configs with their preference flags. final allConfigsWithPrefs = await getAllApiConfigsWithModulePreferences(moduleName); // 3. Filter for only those that are enabled. final enabledConfigs = allConfigsWithPrefs.where((config) => config['is_enabled'] == true).toList(); debugPrint("Found ${enabledConfigs.length} enabled API destinations for module '$moduleName'."); return enabledConfigs; } /// Retrieves only the FTP configurations that are actively enabled for a given module. Future>> getEnabledFtpConfigsForModule(String moduleName) async { final pref = await _dbHelper.getModulePreference(moduleName); // Use direct DB call if (pref == null || !(pref['is_ftp_enabled'] as bool)) { debugPrint("FTP submissions are disabled for module '$moduleName'."); return []; } final allConfigsWithPrefs = await getAllFtpConfigsWithModulePreferences(moduleName); final enabledConfigs = allConfigsWithPrefs.where((config) => config['is_enabled'] == true).toList(); debugPrint("Found ${enabledConfigs.length} enabled FTP destinations for module '$moduleName'."); return enabledConfigs; } }