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; final FirebaseAuth _auth = FirebaseAuth.instance; 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 { if (_auth.currentUser == null) { print('No current user in Auth'); return; } // É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 { 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 { await _auth.signOut(); clearUser(); } /// 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)); } }