import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:prosapp_web_app/models/comment_entity.dart'; import 'package:prosapp_web_app/models/profesional.dart'; import 'package:prosapp_web_app/models/usuario.dart'; import 'package:prosapp_web_app/providers/professional_provider.dart'; import 'package:prosapp_web_app/providers/services_provider.dart'; import 'package:prosapp_web_app/router/router.dart'; import 'package:prosapp_web_app/services/navigation_service.dart'; import 'package:prosapp_web_app/services/notifications_service.dart'; import 'package:provider/provider.dart'; enum AuthStatus { checking, authenticated, notAuthenticated } class AuthProvider extends ChangeNotifier { Usuario? user; Profesional? professional; double userAverageScore = 0.0; AuthStatus authStatus = AuthStatus.checking; final FirebaseAuth _firebaseAuth = FirebaseAuth.instance; final FirebaseFirestore _firestore = FirebaseFirestore.instance; String? _verificationId; AuthProvider() { isAuthenticated(); } Future login(String email, String password) async { try { await _firebaseAuth.signInWithEmailAndPassword( email: email, password: password); final userData = await _firestore .collection('users') .doc(_firebaseAuth.currentUser!.uid) .get(); user = Usuario.fromDocument(userData.data()!); authStatus = AuthStatus.authenticated; notifyListeners(); NavigationService.replaceTo(Flurorouter.dashboardRoute); } catch (e) { authStatus = AuthStatus.notAuthenticated; notifyListeners(); NotificationsService.showSnackBarError( 'Usuario o contraseña incorrectos'); } } Future verifyPhoneNumberForLink(String phoneNumber) async { try { await _firebaseAuth.verifyPhoneNumber( phoneNumber: phoneNumber, timeout: const Duration(seconds: 60), verificationCompleted: (PhoneAuthCredential credential) async { if (_firebaseAuth.currentUser != null) { // Vincula el número de teléfono a la cuenta actual await _firebaseAuth.currentUser!.linkWithCredential(credential); NotificationsService.showSnackbar('Número vinculado exitosamente'); authStatus = AuthStatus.authenticated; notifyListeners(); } }, verificationFailed: (FirebaseAuthException e) { NotificationsService.showSnackBarError( 'Error en la verificación del teléfono: ${e.message}'); }, codeSent: (String verificationId, int? resendToken) { _verificationId = verificationId; notifyListeners(); }, codeAutoRetrievalTimeout: (String verificationId) { _verificationId = verificationId; }, ); } catch (e) { NotificationsService.showSnackBarError('Error al enviar OTP'); } } Future linkPhoneWithOTP(String smsCode) async { try { final credential = PhoneAuthProvider.credential( verificationId: _verificationId!, smsCode: smsCode, ); if (_firebaseAuth.currentUser != null) { await _firebaseAuth.currentUser!.linkWithCredential(credential); await FirebaseFirestore.instance .collection('users') .doc(_firebaseAuth.currentUser!.uid) .update({'phone': _firebaseAuth.currentUser!.phoneNumber}); NotificationsService.showSnackbar('Número vinculado exitosamente'); authStatus = AuthStatus.authenticated; notifyListeners(); NavigationService.replaceTo(Flurorouter.profileRoute); } } catch (e) { authStatus = AuthStatus.notAuthenticated; notifyListeners(); NotificationsService.showSnackBarError('Error en la verificación OTP'); } } Future register(String email, String password, String name) async { try { UserCredential userCredential = await _firebaseAuth.createUserWithEmailAndPassword( email: email, password: password, ); User? user = userCredential.user; if (user != null) { await _firestore.collection('users').doc(user.uid).set({ 'birthday': "", 'city': "", 'email': user.email, 'gender': "", 'id': user.uid, 'name': name.trim(), 'nickname': name.trim().toLowerCase(), 'phone': "", 'picture': "", 'professional_state': 0, 'token': "", }); authStatus = AuthStatus.authenticated; notifyListeners(); NavigationService.replaceTo(Flurorouter.dashboardRoute); } } catch (e) { authStatus = AuthStatus.notAuthenticated; notifyListeners(); NotificationsService.showSnackBarError('Email ya registrado'); } } Future isAuthenticated() async { final User? firebaseUser = _firebaseAuth.currentUser; if (firebaseUser == null) { authStatus = AuthStatus.notAuthenticated; notifyListeners(); return false; } final userData = await _firestore.collection('users').doc(firebaseUser.uid).get(); if (userData.exists) { user = Usuario.fromDocument(userData.data()!); userAverageScore = await _getUserAverageScore(user!.id); authStatus = AuthStatus.authenticated; notifyListeners(); return true; } else { authStatus = AuthStatus.notAuthenticated; notifyListeners(); return false; } } Future logout() async { await _firebaseAuth.signOut(); authStatus = AuthStatus.notAuthenticated; notifyListeners(); Provider.of( NavigationService.navigatorKey.currentContext!, listen: false) .logout(); Provider.of( NavigationService.navigatorKey.currentContext!, listen: false) .logout(); NavigationService.replaceTo(Flurorouter.phoneLoginRoute); } void refreshUser() { isAuthenticated(); } Future verifyPhoneNumber(String phoneNumber) async { try { await _firebaseAuth.verifyPhoneNumber( phoneNumber: phoneNumber, timeout: const Duration(seconds: 60), verificationCompleted: (PhoneAuthCredential credential) async { await _firebaseAuth.signInWithCredential(credential); authStatus = AuthStatus.authenticated; notifyListeners(); NavigationService.replaceTo(Flurorouter.dashboardRoute); }, verificationFailed: (FirebaseAuthException e) { NotificationsService.showSnackBarError( 'La verificación del teléfono falló: ${e.message}'); }, codeSent: (String verificationId, int? resendToken) { _verificationId = verificationId; notifyListeners(); }, codeAutoRetrievalTimeout: (String verificationId) { _verificationId = verificationId; }, ); } catch (e) { NotificationsService.showSnackBarError('Error al enviar OTP'); } } Future signInWithOTP(String smsCode) async { try { final credential = PhoneAuthProvider.credential( verificationId: _verificationId!, smsCode: smsCode, ); await _firebaseAuth.signInWithCredential(credential); User? currentUser = _firebaseAuth.currentUser; if (currentUser != null) { final userData = await _firestore.collection('users').doc(currentUser.uid).get(); if (userData.exists) { user = Usuario.fromDocument(userData.data()!); } else { await _firestore.collection('users').doc(currentUser.uid).set({ 'birthday': "", 'city': "", 'email': "", 'gender': "", 'id': currentUser.uid, 'name': "", 'nickname': "", 'phone': currentUser.phoneNumber, 'picture': "", 'professional_state': 0, 'token': "", }); final newUserData = await _firestore.collection('users').doc(currentUser.uid).get(); user = Usuario.fromDocument(newUserData.data()!); } authStatus = AuthStatus.authenticated; notifyListeners(); NavigationService.replaceTo(Flurorouter.dashboardRoute); } } catch (e) { authStatus = AuthStatus.notAuthenticated; notifyListeners(); NotificationsService.showSnackBarError('Error en la verificación OTP'); } } Future addEmailAndPassword(String email, String password) async { try { final User? currentUser = _firebaseAuth.currentUser; if (currentUser != null) { await currentUser.updateEmail(email); await currentUser.updatePassword(password); await _firestore.collection('users').doc(currentUser.uid).update({ 'email': email, }); notifyListeners(); NotificationsService.showSnackbar( 'Email y contraseña añadidos exitosamente'); NavigationService.replaceTo(Flurorouter.profileRoute); } } catch (e) { if (e is FirebaseAuthException && e.code == 'email-already-in-use') { NotificationsService.showSnackBarError('El correo ya existe'); } if (e is FirebaseAuthException && e.code == 'invalid-email') { NotificationsService.showSnackBarError('El correo no es vßlido'); } if (e is FirebaseAuthException && e.code == 'weak-password') { NotificationsService.showSnackBarError( 'La contraseña debe tener al menos 6 caracteres'); } if (e is FirebaseAuthException && e.code == 'requires-recent-login') { NotificationsService.showSnackBarError( 'Debes iniciar sesión recientemente antes de agregar email y contraseña'); } } } Future _getUserAverageScore(String userId) async { final querySnapshot = await FirebaseFirestore.instance .collection('comments') .where('destination_id', isEqualTo: userId) .where('is_from_user', isEqualTo: false) .get(); if (querySnapshot.docs.isEmpty) { return 0.0; } final scores = querySnapshot.docs .map((e) => CommentEntity.fromDocument(e.data()).score) .toList(); final averageScore = scores.reduce((a, b) => a + b) / scores.length; return averageScore; } }