// ABOUTME: Preferences service for persistent storage of user settings and configuration
// ABOUTME: Wraps SharedPreferences with type safety, validation, and change notifications
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/settings/app_settings.dart';
import '../models/settings/theme_settings.dart';
import '../models/settings/unit_settings.dart';
import '../models/settings/privacy_settings.dart';

/// Service for managing user preferences and settings persistence
class PreferencesService extends ChangeNotifier {
  static PreferencesService? _instance;
  SharedPreferences? _prefs;
  AppSettings _settings = AppSettings.defaults();

  /// Singleton instance
  static PreferencesService get instance {
    _instance ??= PreferencesService._internal();
    return _instance!;
  }

  PreferencesService._internal();

  // Preference keys
  static const String _settingsKey = 'app_settings';
  static const String _firstLaunchKey = 'first_launch';
  static const String _lastBackupKey = 'last_backup';
  static const String _dataVersionKey = 'data_version';
  static const String _failedUnlockAttemptsKey = 'failed_unlock_attempts';
  static const String _lockoutEndTimeKey = 'lockout_end_time';
  static const String _encryptionEnabledKey = 'encryption_enabled';

  /// Current app settings
  AppSettings get settings => _settings;

  /// Initialize the preferences service
  Future<void> initialize() async {
    _prefs = await SharedPreferences.getInstance();
    await _loadSettings();
  }

  /// Load settings from SharedPreferences
  Future<void> _loadSettings() async {
    try {
      final settingsJson = _prefs?.getString(_settingsKey);
      if (settingsJson != null) {
        final settingsMap = json.decode(settingsJson) as Map<String, dynamic>;
        _settings = AppSettings.fromJson(settingsMap);
      } else {
        // First time launch - save default settings
        _settings = AppSettings.defaults();
        await _saveSettings();
        await setFirstLaunch(false);
      }
    } catch (e) {
      debugPrint('Error loading settings: $e');
      _settings = AppSettings.defaults();
    }
    notifyListeners();
  }

  /// Save settings to SharedPreferences
  Future<void> _saveSettings() async {
    try {
      final settingsJson = json.encode(_settings.toJson());
      await _prefs?.setString(_settingsKey, settingsJson);
      notifyListeners();
    } catch (e) {
      debugPrint('Error saving settings: $e');
    }
  }

  /// Update complete settings
  Future<void> updateSettings(AppSettings newSettings) async {
    _settings = newSettings;
    await _saveSettings();
  }

  /// Update theme settings
  Future<void> updateThemeSettings(ThemeSettings themeSettings) async {
    _settings = _settings.copyWith(themeSettings: themeSettings);
    await _saveSettings();
  }

  /// Update unit settings
  Future<void> updateUnitSettings(UnitSettings unitSettings) async {
    _settings = _settings.copyWith(unitSettings: unitSettings);
    await _saveSettings();
  }

  /// Update privacy settings
  Future<void> updatePrivacySettings(PrivacySettings privacySettings) async {
    _settings = _settings.copyWith(privacySettings: privacySettings);
    await _saveSettings();
  }

  /// Toggle theme mode
  Future<void> toggleThemeMode() async {
    final currentMode = _settings.themeSettings.themeMode;
    AppThemeMode newMode;
    
    switch (currentMode) {
      case AppThemeMode.system:
        newMode = AppThemeMode.light;
        break;
      case AppThemeMode.light:
        newMode = AppThemeMode.dark;
        break;
      case AppThemeMode.dark:
        newMode = AppThemeMode.system;
        break;
    }

    final newThemeSettings = _settings.themeSettings.copyWith(themeMode: newMode);
    await updateThemeSettings(newThemeSettings);
  }

  /// Update language preference
  Future<void> updateLanguage(String language) async {
    _settings = _settings.copyWith(language: language);
    await _saveSettings();
  }

  /// Update notification settings
  Future<void> updateNotificationsEnabled(bool enabled) async {
    _settings = _settings.copyWith(enableNotifications: enabled);
    await _saveSettings();
  }

  /// Update analytics settings
  Future<void> updateAnalyticsEnabled(bool enabled) async {
    _settings = _settings.copyWith(enableAnalytics: enabled);
    await _saveSettings();
  }

  // First launch management
  Future<bool> isFirstLaunch() async {
    return _prefs?.getBool(_firstLaunchKey) ?? true;
  }

  Future<void> setFirstLaunch(bool isFirst) async {
    await _prefs?.setBool(_firstLaunchKey, isFirst);
  }

  // Backup management
  Future<DateTime?> getLastBackupTime() async {
    final timestamp = _prefs?.getInt(_lastBackupKey);
    return timestamp != null ? DateTime.fromMillisecondsSinceEpoch(timestamp) : null;
  }

  Future<void> setLastBackupTime(DateTime time) async {
    await _prefs?.setInt(_lastBackupKey, time.millisecondsSinceEpoch);
  }

  // Data version management for migrations
  Future<int> getDataVersion() async {
    return _prefs?.getInt(_dataVersionKey) ?? 1;
  }

  Future<void> setDataVersion(int version) async {
    await _prefs?.setInt(_dataVersionKey, version);
  }

  /// Reset all settings to defaults
  Future<void> resetToDefaults() async {
    _settings = AppSettings.defaults();
    await _saveSettings();
  }

  /// Clear all preferences (for testing or complete reset)
  Future<void> clearAll() async {
    await _prefs?.clear();
    _settings = AppSettings.defaults();
    notifyListeners();
  }

  /// Export settings as JSON string
  String exportSettings() {
    return json.encode(_settings.toJson());
  }

  /// Import settings from JSON string
  Future<bool> importSettings(String settingsJson) async {
    try {
      final settingsMap = json.decode(settingsJson) as Map<String, dynamic>;
      final newSettings = AppSettings.fromJson(settingsMap);
      
      // Validate settings before applying
      if (_validateSettings(newSettings)) {
        await updateSettings(newSettings);
        return true;
      }
      return false;
    } catch (e) {
      debugPrint('Error importing settings: $e');
      return false;
    }
  }

  /// Validate settings before applying
  bool _validateSettings(AppSettings settings) {
    // Basic validation - could be expanded
    return settings.language.isNotEmpty &&
           settings.themeSettings.textScale.scaleFactor > 0 &&
           settings.unitSettings.locale.isNotEmpty;
  }

  /// Get settings summary for display
  Map<String, dynamic> getSettingsSummary() {
    return {
      'theme': _settings.themeSettings.themeMode.displayName,
      'units': _settings.unitSettings.unitsDisplayText,
      'language': _settings.language,
      'security': _settings.privacySettings.securityLevel,
      'notifications': _settings.enableNotifications,
      'analytics': _settings.enableAnalytics,
    };
  }

  // Encryption and lockout management
  
  /// Check if encryption is enabled
  Future<bool> isEncryptionEnabled() async {
    return _prefs?.getBool(_encryptionEnabledKey) ?? false;
  }

  /// Set encryption enabled state
  Future<void> setEncryptionEnabled(bool enabled) async {
    await _prefs?.setBool(_encryptionEnabledKey, enabled);
  }

  /// Get failed unlock attempts count
  Future<int> getFailedUnlockAttempts() async {
    return _prefs?.getInt(_failedUnlockAttemptsKey) ?? 0;
  }

  /// Increment failed unlock attempts
  Future<void> incrementFailedUnlockAttempts() async {
    final current = await getFailedUnlockAttempts();
    await _prefs?.setInt(_failedUnlockAttemptsKey, current + 1);
  }

  /// Get lockout end time in milliseconds
  Future<int?> getLockoutEndTime() async {
    return _prefs?.getInt(_lockoutEndTimeKey);
  }

  /// Set lockout end time in milliseconds
  Future<void> setLockoutEndTime(int milliseconds) async {
    await _prefs?.setInt(_lockoutEndTimeKey, milliseconds);
  }

  /// Clear lockout status
  Future<void> clearLockout() async {
    await _prefs?.remove(_failedUnlockAttemptsKey);
    await _prefs?.remove(_lockoutEndTimeKey);
  }

  @override
  void dispose() {
    super.dispose();
  }
}
