import 'cache_service.dart';
import '../utils/logger.dart';

/// Décorateur générique pour ajouter du cache à n'importe quelle méthode
/// Utilise un pattern cache-aside : vérifie le cache, sinon appelle l'API
class CachedDatasourceDecorator {
  final CacheService _cacheService;

  CachedDatasourceDecorator(this._cacheService);

  /// Exécute une fonction avec cache
  /// Si les données sont en cache et valides, les retourne
  /// Sinon, appelle fetchFunction et met en cache le résultat
  Future<T> withCache<T>({
    required String cacheKey,
    required Future<T> Function() fetchFunction,
    T Function(dynamic)? deserializer,
  }) async {
    try {
      // 1. Vérifier le cache
      final cached = _cacheService.get(cacheKey);
      if (cached != null) {
        AppLogger.debug('✅ Cache HIT: $cacheKey');
        if (deserializer != null) {
          return deserializer(cached);
        }
        return cached as T;
      }

      // 2. Cache MISS - appeler l'API
      AppLogger.debug('❌ Cache MISS: $cacheKey - Fetching from API');
      final result = await fetchFunction();

      // 3. Mettre en cache
      await _cacheService.set(cacheKey, result);

      return result;
    } catch (e) {
      AppLogger.error('Erreur dans withCache pour $cacheKey', error: e);
      rethrow;
    }
  }

  /// Invalide (supprime) une entrée de cache
  Future<void> invalidate(String cacheKey) async {
    await _cacheService.remove(cacheKey);
    AppLogger.info('Cache invalidé: $cacheKey');
  }

  /// Invalide toutes les entrées commençant par un préfixe
  Future<void> invalidatePrefix(String prefix) async {
    await _cacheService.clearByPrefix(prefix);
    AppLogger.info('Cache invalidé pour préfixe: $prefix');
  }
}

/// Extension pour faciliter l'utilisation du cache
extension CachedCall<T> on Future<T> Function() {
  /// Ajoute du cache à une fonction asynchrone
  Future<T> withCache(
    CachedDatasourceDecorator decorator,
    String cacheKey,
  ) {
    return decorator.withCache(
      cacheKey: cacheKey,
      fetchFunction: this,
    );
  }
}
