import 'dart:convert';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/dashboard_stats_model.dart';
import '../../config/dashboard_config.dart';

/// Gestionnaire de cache avancé pour le Dashboard
class DashboardCacheManager {
  static const String _keyPrefix = 'dashboard_cache_';
  static const String _keyDashboardData = '${_keyPrefix}data';
  static const String _keyDashboardStats = '${_keyPrefix}stats';
  static const String _keyRecentActivities = '${_keyPrefix}activities';
  static const String _keyUpcomingEvents = '${_keyPrefix}events';
  static const String _keyLastUpdate = '${_keyPrefix}last_update';
  static const String _keyUserPreferences = '${_keyPrefix}user_prefs';
  
  SharedPreferences? _prefs;
  final Map<String, dynamic> _memoryCache = {};
  final Map<String, DateTime> _cacheTimestamps = {};
  Timer? _cleanupTimer;
  
  /// Initialise le gestionnaire de cache
  Future<void> initialize() async {
    _prefs = await SharedPreferences.getInstance();
    _startCleanupTimer();
    await _loadMemoryCache();
  }
  
  /// Démarre le timer de nettoyage automatique
  void _startCleanupTimer() {
    _cleanupTimer = Timer.periodic(
      const Duration(minutes: 30),
      (_) => _cleanupExpiredCache(),
    );
  }
  
  /// Charge le cache en mémoire au démarrage
  Future<void> _loadMemoryCache() async {
    if (_prefs == null) return;
    
    final keys = _prefs!.getKeys().where((key) => key.startsWith(_keyPrefix));
    
    for (final key in keys) {
      final value = _prefs!.getString(key);
      if (value != null) {
        try {
          final data = jsonDecode(value);
          _memoryCache[key] = data;
          
          // Charger le timestamp si disponible
          final timestampKey = '${key}_timestamp';
          final timestamp = _prefs!.getInt(timestampKey);
          if (timestamp != null) {
            _cacheTimestamps[key] = DateTime.fromMillisecondsSinceEpoch(timestamp);
          }
        } catch (e) {
          // Supprimer les données corrompues
          await _prefs!.remove(key);
        }
      }
    }
  }
  
  /// Sauvegarde les données complètes du dashboard
  Future<void> cacheDashboardData(
    DashboardDataModel data,
    String organizationId,
    String userId,
  ) async {
    final key = '${_keyDashboardData}_${organizationId}_$userId';
    await _cacheData(key, data.toJson());
  }
  
  /// Récupère les données complètes du dashboard
  Future<DashboardDataModel?> getCachedDashboardData(
    String organizationId,
    String userId,
  ) async {
    final key = '${_keyDashboardData}_${organizationId}_$userId';
    final data = await _getCachedData(key);
    
    if (data != null) {
      try {
        return DashboardDataModel.fromJson(data);
      } catch (e) {
        // Supprimer les données corrompues
        await _removeCachedData(key);
        return null;
      }
    }
    
    return null;
  }
  
  /// Sauvegarde les statistiques du dashboard
  Future<void> cacheDashboardStats(
    DashboardStatsModel stats,
    String organizationId,
    String userId,
  ) async {
    final key = '${_keyDashboardStats}_${organizationId}_$userId';
    await _cacheData(key, stats.toJson());
  }
  
  /// Récupère les statistiques du dashboard
  Future<DashboardStatsModel?> getCachedDashboardStats(
    String organizationId,
    String userId,
  ) async {
    final key = '${_keyDashboardStats}_${organizationId}_$userId';
    final data = await _getCachedData(key);
    
    if (data != null) {
      try {
        return DashboardStatsModel.fromJson(data);
      } catch (e) {
        await _removeCachedData(key);
        return null;
      }
    }
    
    return null;
  }
  
  /// Sauvegarde les activités récentes
  Future<void> cacheRecentActivities(
    List<RecentActivityModel> activities,
    String organizationId,
    String userId,
  ) async {
    final key = '${_keyRecentActivities}_${organizationId}_$userId';
    final data = activities.map((activity) => activity.toJson()).toList();
    await _cacheData(key, data);
  }
  
  /// Récupère les activités récentes
  Future<List<RecentActivityModel>?> getCachedRecentActivities(
    String organizationId,
    String userId,
  ) async {
    final key = '${_keyRecentActivities}_${organizationId}_$userId';
    final data = await _getCachedData(key);
    
    if (data != null && data is List) {
      try {
        return data
            .map((item) => RecentActivityModel.fromJson(item))
            .toList();
      } catch (e) {
        await _removeCachedData(key);
        return null;
      }
    }
    
    return null;
  }
  
  /// Sauvegarde les événements à venir
  Future<void> cacheUpcomingEvents(
    List<UpcomingEventModel> events,
    String organizationId,
    String userId,
  ) async {
    final key = '${_keyUpcomingEvents}_${organizationId}_$userId';
    final data = events.map((event) => event.toJson()).toList();
    await _cacheData(key, data);
  }
  
  /// Récupère les événements à venir
  Future<List<UpcomingEventModel>?> getCachedUpcomingEvents(
    String organizationId,
    String userId,
  ) async {
    final key = '${_keyUpcomingEvents}_${organizationId}_$userId';
    final data = await _getCachedData(key);
    
    if (data != null && data is List) {
      try {
        return data
            .map((item) => UpcomingEventModel.fromJson(item))
            .toList();
      } catch (e) {
        await _removeCachedData(key);
        return null;
      }
    }
    
    return null;
  }
  
  /// Sauvegarde les préférences utilisateur
  Future<void> cacheUserPreferences(
    Map<String, dynamic> preferences,
    String userId,
  ) async {
    final key = '${_keyUserPreferences}_$userId';
    await _cacheData(key, preferences);
  }
  
  /// Récupère les préférences utilisateur
  Future<Map<String, dynamic>?> getCachedUserPreferences(String userId) async {
    final key = '${_keyUserPreferences}_$userId';
    final data = await _getCachedData(key);
    
    if (data != null && data is Map<String, dynamic>) {
      return data;
    }
    
    return null;
  }
  
  /// Méthode générique pour sauvegarder des données
  Future<void> _cacheData(String key, dynamic data) async {
    if (_prefs == null) return;
    
    try {
      final jsonString = jsonEncode(data);
      await _prefs!.setString(key, jsonString);
      
      // Sauvegarder le timestamp
      final timestamp = DateTime.now().millisecondsSinceEpoch;
      await _prefs!.setInt('${key}_timestamp', timestamp);
      
      // Mettre à jour le cache mémoire
      _memoryCache[key] = data;
      _cacheTimestamps[key] = DateTime.now();
      
    } catch (e) {
      // Erreur de sérialisation, ignorer
    }
  }
  
  /// Méthode générique pour récupérer des données
  Future<dynamic> _getCachedData(String key) async {
    // Vérifier d'abord le cache mémoire
    if (_memoryCache.containsKey(key)) {
      if (_isCacheValid(key)) {
        return _memoryCache[key];
      } else {
        // Cache expiré, le supprimer
        await _removeCachedData(key);
        return null;
      }
    }
    
    // Vérifier le cache persistant
    if (_prefs == null) return null;
    
    final jsonString = _prefs!.getString(key);
    if (jsonString != null) {
      try {
        final data = jsonDecode(jsonString);
        
        // Vérifier la validité du cache
        if (_isCacheValid(key)) {
          // Charger en mémoire pour les prochains accès
          _memoryCache[key] = data;
          return data;
        } else {
          // Cache expiré, le supprimer
          await _removeCachedData(key);
          return null;
        }
      } catch (e) {
        // Données corrompues, les supprimer
        await _removeCachedData(key);
        return null;
      }
    }
    
    return null;
  }
  
  /// Vérifie si le cache est encore valide
  bool _isCacheValid(String key) {
    final timestamp = _cacheTimestamps[key];
    if (timestamp == null) {
      // Essayer de récupérer le timestamp depuis SharedPreferences
      final timestampMs = _prefs?.getInt('${key}_timestamp');
      if (timestampMs != null) {
        final cacheTime = DateTime.fromMillisecondsSinceEpoch(timestampMs);
        _cacheTimestamps[key] = cacheTime;
        return DateTime.now().difference(cacheTime) < DashboardConfig.cacheExpiration;
      }
      return false;
    }
    
    return DateTime.now().difference(timestamp) < DashboardConfig.cacheExpiration;
  }
  
  /// Supprime des données du cache
  Future<void> _removeCachedData(String key) async {
    _memoryCache.remove(key);
    _cacheTimestamps.remove(key);
    
    if (_prefs != null) {
      await _prefs!.remove(key);
      await _prefs!.remove('${key}_timestamp');
    }
  }
  
  /// Nettoie le cache expiré
  Future<void> _cleanupExpiredCache() async {
    final keysToRemove = <String>[];
    
    for (final key in _cacheTimestamps.keys) {
      if (!_isCacheValid(key)) {
        keysToRemove.add(key);
      }
    }
    
    for (final key in keysToRemove) {
      await _removeCachedData(key);
    }
  }
  
  /// Vide tout le cache
  Future<void> clearCache() async {
    _memoryCache.clear();
    _cacheTimestamps.clear();
    
    if (_prefs != null) {
      final keys = _prefs!.getKeys().where((key) => key.startsWith(_keyPrefix));
      for (final key in keys) {
        await _prefs!.remove(key);
      }
    }
  }
  
  /// Vide le cache pour un utilisateur spécifique
  Future<void> clearUserCache(String organizationId, String userId) async {
    final userKeys = [
      '${_keyDashboardData}_${organizationId}_$userId',
      '${_keyDashboardStats}_${organizationId}_$userId',
      '${_keyRecentActivities}_${organizationId}_$userId',
      '${_keyUpcomingEvents}_${organizationId}_$userId',
      '${_keyUserPreferences}_$userId',
    ];
    
    for (final key in userKeys) {
      await _removeCachedData(key);
    }
  }
  
  /// Obtient les statistiques du cache
  Map<String, dynamic> getCacheStats() {
    final totalKeys = _memoryCache.length;
    final validKeys = _cacheTimestamps.keys.where(_isCacheValid).length;
    final expiredKeys = totalKeys - validKeys;
    
    return {
      'totalKeys': totalKeys,
      'validKeys': validKeys,
      'expiredKeys': expiredKeys,
      'memoryUsage': _calculateMemoryUsage(),
      'oldestEntry': _getOldestEntryAge(),
      'newestEntry': _getNewestEntryAge(),
    };
  }
  
  /// Calcule l'utilisation mémoire approximative
  int _calculateMemoryUsage() {
    int totalSize = 0;
    for (final data in _memoryCache.values) {
      try {
        totalSize += jsonEncode(data).length;
      } catch (e) {
        // Ignorer les erreurs de sérialisation
      }
    }
    return totalSize;
  }
  
  /// Obtient l'âge de l'entrée la plus ancienne
  Duration? _getOldestEntryAge() {
    if (_cacheTimestamps.isEmpty) return null;
    
    final oldestTimestamp = _cacheTimestamps.values
        .reduce((a, b) => a.isBefore(b) ? a : b);
    
    return DateTime.now().difference(oldestTimestamp);
  }
  
  /// Obtient l'âge de l'entrée la plus récente
  Duration? _getNewestEntryAge() {
    if (_cacheTimestamps.isEmpty) return null;
    
    final newestTimestamp = _cacheTimestamps.values
        .reduce((a, b) => a.isAfter(b) ? a : b);
    
    return DateTime.now().difference(newestTimestamp);
  }
  
  /// Libère les ressources
  void dispose() {
    _cleanupTimer?.cancel();
    _memoryCache.clear();
    _cacheTimestamps.clear();
  }
}
