import 'package:get/get.dart'; import 'package:youmazgestion/Services/stock_managementDatabase.dart'; class PermissionCacheService extends GetxController { static final PermissionCacheService instance = PermissionCacheService._init(); PermissionCacheService._init(); // Cache en mémoire optimisé final Map> _permissionCache = {}; final Map>> _menuCache = {}; bool _isLoaded = false; String _currentUsername = ''; /// ✅ OPTIMISÉ: Une seule requête complexe pour charger tout Future loadUserPermissions(String username) async { if (_isLoaded && _currentUsername == username && _permissionCache.containsKey(username)) { print("📋 Permissions déjà en cache pour: $username"); return; } print("🔄 Chargement OPTIMISÉ des permissions pour: $username"); final stopwatch = Stopwatch()..start(); try { final db = AppDatabase.instance; // 🚀 UNE SEULE REQUÊTE pour tout récupérer final userPermissions = await _getUserPermissionsOptimized(db, username); // Organiser les données Map permissions = {}; Set> accessibleMenus = {}; for (var row in userPermissions) { final menuId = row['menu_id'] as int; final menuName = row['menu_name'] as String; final menuRoute = row['menu_route'] as String; final permissionName = row['permission_name'] as String; // Ajouter la permission final key = "${permissionName}_$menuRoute"; permissions[key] = true; // Ajouter le menu aux accessibles accessibleMenus.add({ 'id': menuId, 'name': menuName, 'route': menuRoute, }); } // Mettre en cache _permissionCache[username] = permissions; _menuCache[username] = accessibleMenus.toList(); _currentUsername = username; _isLoaded = true; stopwatch.stop(); print("✅ Permissions chargées en ${stopwatch.elapsedMilliseconds}ms"); print(" - ${permissions.length} permissions"); print(" - ${accessibleMenus.length} menus accessibles"); } catch (e) { stopwatch.stop(); print("❌ Erreur après ${stopwatch.elapsedMilliseconds}ms: $e"); rethrow; } } /// 🚀 NOUVELLE MÉTHODE: Une seule requête optimisée Future>> _getUserPermissionsOptimized( AppDatabase db, String username) async { final connection = await db.database; final result = await connection.query(''' SELECT DISTINCT m.id as menu_id, m.name as menu_name, m.route as menu_route, p.name as permission_name FROM users u INNER JOIN roles r ON u.role_id = r.id INNER JOIN role_menu_permissions rmp ON r.id = rmp.role_id INNER JOIN menu m ON rmp.menu_id = m.id INNER JOIN permissions p ON rmp.permission_id = p.id WHERE u.username = ? ORDER BY m.name, p.name ''', [username]); return result.map((row) => row.fields).toList(); } /// ✅ Vérification rapide depuis le cache bool hasPermission(String username, String permissionName, String menuRoute) { final userPermissions = _permissionCache[username]; if (userPermissions == null) { print("⚠️ Cache non initialisé pour: $username"); return false; } final key = "${permissionName}_$menuRoute"; return userPermissions[key] ?? false; } /// ✅ Récupération rapide des menus List> getUserMenus(String username) { return _menuCache[username] ?? []; } /// ✅ Vérification d'accès menu bool hasMenuAccess(String username, String menuRoute) { final userMenus = _menuCache[username] ?? []; return userMenus.any((menu) => menu['route'] == menuRoute); } /// ✅ Préchargement asynchrone en arrière-plan Future preloadUserDataAsync(String username) async { // Lancer en arrière-plan sans bloquer l'UI unawaited(_preloadInBackground(username)); } Future _preloadInBackground(String username) async { try { print("🔄 Préchargement en arrière-plan pour: $username"); await loadUserPermissions(username); print("✅ Préchargement terminé"); } catch (e) { print("⚠️ Erreur préchargement: $e"); } } /// ✅ Préchargement synchrone (pour la connexion) Future preloadUserData(String username) async { try { print("🔄 Préchargement synchrone pour: $username"); await loadUserPermissions(username); print("✅ Données préchargées avec succès"); } catch (e) { print("❌ Erreur lors du préchargement: $e"); // Ne pas bloquer la connexion } } /// ✅ Vider le cache void clearAllCache() { _permissionCache.clear(); _menuCache.clear(); _isLoaded = false; _currentUsername = ''; print("🗑️ Cache vidé complètement"); } /// ✅ Rechargement forcé Future refreshUserPermissions(String username) async { _permissionCache.remove(username); _menuCache.remove(username); _isLoaded = false; await loadUserPermissions(username); print("🔄 Permissions rechargées pour: $username"); } /// ✅ Status du cache bool get isLoaded => _isLoaded && _currentUsername.isNotEmpty; String get currentCachedUser => _currentUsername; /// ✅ Statistiques Map getCacheStats() { return { 'is_loaded': _isLoaded, 'current_user': _currentUsername, 'users_cached': _permissionCache.length, 'total_permissions': _permissionCache.values .map((perms) => perms.length) .fold(0, (a, b) => a + b), 'total_menus': _menuCache.values .map((menus) => menus.length) .fold(0, (a, b) => a + b), }; } /// ✅ Debug amélioré void debugPrintCache() { print("=== DEBUG CACHE OPTIMISÉ ==="); print("Chargé: $_isLoaded"); print("Utilisateur actuel: $_currentUsername"); print("Utilisateurs en cache: ${_permissionCache.keys.toList()}"); for (var username in _permissionCache.keys) { final permissions = _permissionCache[username]!; final menus = _menuCache[username] ?? []; print("$username: ${permissions.length} permissions, ${menus.length} menus"); // Détail des menus pour debug for (var menu in menus.take(3)) { print(" → ${menu['name']} (${menu['route']})"); } } print("============================"); } /// ✅ NOUVEAU: Validation de l'intégrité du cache Future validateCacheIntegrity(String username) async { if (!_permissionCache.containsKey(username)) { return false; } try { final db = AppDatabase.instance; final connection = await db.database; // Vérification rapide: compter les permissions de l'utilisateur final result = await connection.query(''' SELECT COUNT(DISTINCT CONCAT(p.name, '_', m.route)) as permission_count FROM users u INNER JOIN roles r ON u.role_id = r.id INNER JOIN role_menu_permissions rmp ON r.id = rmp.role_id INNER JOIN menu m ON rmp.menu_id = m.id INNER JOIN permissions p ON rmp.permission_id = p.id WHERE u.username = ? ''', [username]); final dbCount = result.first['permission_count'] as int; final cacheCount = _permissionCache[username]!.length; final isValid = dbCount == cacheCount; if (!isValid) { print("⚠️ Cache invalide: DB=$dbCount, Cache=$cacheCount"); } return isValid; } catch (e) { print("❌ Erreur validation cache: $e"); return false; } } /// ✅ NOUVEAU: Rechargement intelligent Future smartRefresh(String username) async { final isValid = await validateCacheIntegrity(username); if (!isValid) { print("🔄 Cache invalide, rechargement nécessaire"); await refreshUserPermissions(username); } else { print("✅ Cache valide, pas de rechargement nécessaire"); } } } /// ✅ Extension pour éviter l'import de dart:async void unawaited(Future future) { // Ignorer le warning sur le Future non attendu future.catchError((error) { print("Erreur tâche en arrière-plan: $error"); }); }