import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import '../models/user_model.dart'; import '../models/role_model.dart'; import '../models/notification_preferences_model.dart'; import '../utils/firebase_storage_manager.dart'; import '../services/api_service.dart'; import '../services/data_service.dart'; import '../utils/performance_monitor.dart'; class LocalUserProvider with ChangeNotifier { UserModel? _currentUser; RoleModel? _currentRole; FirebaseAuth? _auth; final FirebaseStorageManager _storageManager = FirebaseStorageManager(); final DataService _dataService = DataService(apiService); bool _isLoadingUserData = false; DateTime? _lastUserDataLoad; UserModel? get currentUser => _currentUser; String? get uid => _currentUser?.uid; String? get firstName => _currentUser?.firstName; String? get lastName => _currentUser?.lastName; String? get role => _currentUser?.role ?? 'USER'; String? get profilePhotoUrl => _currentUser?.profilePhotoUrl; String? get email => _currentUser?.email; String? get phoneNumber => _currentUser?.phoneNumber; RoleModel? get currentRole => _currentRole; List get permissions => _currentRole?.permissions ?? []; bool get isLoadingUserData => _isLoadingUserData; /// Vérifie si les données utilisateur doivent être rechargées bool _shouldReloadUserData() { if (_currentUser == null) return true; if (_lastUserDataLoad == null) return true; final now = DateTime.now(); final difference = now.difference(_lastUserDataLoad!); return difference.inMinutes > 5; // Cache de 5 minutes pour les données utilisateur } /// Charge les données de l'utilisateur actuel via Cloud Function Future loadUserData({bool forceReload = false}) async { // Si FirebaseAuth n'est pas encore disponible final FirebaseAuth auth; try { auth = _getAuthInstance(); } catch (e) { print('Auth instance not ready in loadUserData: $e'); return; } if (auth.currentUser == null) { print('No current user in Auth'); return; } // Bootstrap léger : rendre l'UID disponible tout de suite pour les écrans // qui en ont besoin, même si le profil complet n'est pas encore chargé. if (_currentUser == null) { final firebaseUser = auth.currentUser!; _currentUser = UserModel( uid: firebaseUser.uid, email: firebaseUser.email ?? '', firstName: '', lastName: '', role: 'USER', phoneNumber: '', profilePhotoUrl: firebaseUser.photoURL ?? '', ); _currentRole = RoleModel( id: 'USER', name: '', permissions: const [], ); notifyListeners(); } // Éviter les rechargements inutiles if (!forceReload && !_shouldReloadUserData()) { print('Using cached user data'); return; } // Éviter les appels simultanés if (_isLoadingUserData) { print('User data already loading, skipping'); return; } _isLoadingUserData = true; PerformanceMonitor.start('LocalUserProvider.loadUserData'); print('Loading user data for: ${_auth!.currentUser!.uid}'); try { // Utiliser la Cloud Function getCurrentUser PerformanceMonitor.start('LocalUserProvider.getCurrentUser_API'); final result = await apiService.call('getCurrentUser', {}); PerformanceMonitor.end('LocalUserProvider.getCurrentUser_API'); final userData = result['user'] as Map; print('User data loaded from API: ${userData['uid']}'); // Extraire le rôle final roleData = userData['role'] as Map?; if (roleData != null) { _currentRole = RoleModel.fromMap(roleData, roleData['id'] as String); } // Créer le UserModel _currentUser = UserModel( uid: userData['uid'] as String, email: userData['email'] as String? ?? '', firstName: userData['firstName'] as String? ?? '', lastName: userData['lastName'] as String? ?? '', role: roleData?['id'] as String? ?? 'USER', phoneNumber: userData['phoneNumber'] as String? ?? '', profilePhotoUrl: userData['profilePhotoUrl'] as String? ?? '', ); print('User data loaded successfully'); _lastUserDataLoad = DateTime.now(); _isLoadingUserData = false; notifyListeners(); PerformanceMonitor.end('LocalUserProvider.loadUserData'); } catch (e) { print('Error loading user data: $e'); _isLoadingUserData = false; PerformanceMonitor.end('LocalUserProvider.loadUserData'); rethrow; } } /// Met à jour l'utilisateur void setUser(UserModel user) { _currentUser = user; notifyListeners(); } /// Efface les données utilisateur void clearUser() { _currentUser = null; _currentRole = null; _lastUserDataLoad = null; _isLoadingUserData = false; notifyListeners(); } /// Mise à jour des informations utilisateur via Cloud Function Future updateUserData({ String? firstName, String? lastName, String? phoneNumber, }) async { if (_currentUser == null) return; try { await _dataService.updateUser( _currentUser!.uid, { 'firstName': firstName ?? _currentUser!.firstName, 'lastName': lastName ?? _currentUser!.lastName, 'phoneNumber': phoneNumber ?? _currentUser!.phoneNumber, }, ); _currentUser = _currentUser!.copyWith( firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, ); notifyListeners(); } catch (e) { debugPrint('Erreur mise à jour utilisateur : $e'); rethrow; } } /// Mise à jour des préférences de notifications Future updateNotificationPreferences(NotificationPreferences preferences) async { if (_currentUser == null) return; try { await _dataService.updateUser( _currentUser!.uid, { 'notificationPreferences': preferences.toMap(), }, ); _currentUser = _currentUser!.copyWith(notificationPreferences: preferences); notifyListeners(); } catch (e) { debugPrint('Erreur mise à jour préférences notifications : $e'); rethrow; } } /// Changement de photo de profil Future changeProfilePicture(XFile image) async { if (_currentUser == null) return; try { String? newProfilePhotoUrl = await _storageManager.sendProfilePicture( imageFile: image, uid: _currentUser!.uid, ); if (newProfilePhotoUrl != null) { // Mettre à jour via Cloud Function await _dataService.updateUser( _currentUser!.uid, {'profilePhotoUrl': newProfilePhotoUrl}, ); _currentUser = _currentUser!.copyWith(profilePhotoUrl: newProfilePhotoUrl); notifyListeners(); } } catch (e) { debugPrint('Erreur mise à jour photo de profil : $e'); rethrow; } } /// Connexion Future signInWithEmailAndPassword( String email, String password) async { try { final auth = _getAuthInstance(); UserCredential userCredential = await auth.signInWithEmailAndPassword( email: email, password: password); // Note: loadUserData() sera appelé en arrière-plan dans main.dart // pour ne pas bloquer la navigation return userCredential; } catch (e) { throw FirebaseAuthException(code: 'login-failed', message: e.toString()); } } /// Déconnexion Future signOut() async { try { final auth = _getAuthInstance(); await auth.signOut(); } catch (e) { debugPrint('Error during signOut: $e'); } clearUser(); } FirebaseAuth _getAuthInstance() { try { _auth ??= FirebaseAuth.instance; return _auth!; } catch (e, st) { debugPrint('[LocalUserProvider] FirebaseAuth.instance access error: $e\n$st'); throw Exception('FirebaseAuth not available'); } } /// Vérifie si l'utilisateur a une permission spécifique bool hasPermission(String permission) { return _currentRole?.permissions.contains(permission) ?? false; } /// Vérifie si l'utilisateur a toutes les permissions données bool hasAllPermissions(List permissions) { if (_currentRole == null) return false; return permissions.every((p) => _currentRole!.permissions.contains(p)); } /// Vérifie si l'utilisateur a au moins une des permissions données bool hasAnyPermission(List permissions) { if (_currentRole == null) return false; return permissions.any((p) => _currentRole!.permissions.contains(p)); } }