import 'package:flutter/material.dart'; import 'package:flutter/scheduler.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/api_service.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; double userAverageScore = 0.0; AuthStatus authStatus = AuthStatus.checking; final _api = ApiService.instance; AuthProvider() { isAuthenticated(); } void _navigateAfterAuth() { if (user?.isPhoneVerified == false) { NavigationService.replaceTo(Flurorouter.phoneLoginRoute); } else if (user?.city == null || user!.city!.isEmpty) { NavigationService.replaceTo(Flurorouter.setupCityRoute); } else { NavigationService.replaceTo(Flurorouter.dashboardRoute); } } Future login(String email, String password) async { try { final data = await _api.post('/auth/login', {'email': email, 'password': password}); await _api.saveToken(data['access_token'] as String); user = Usuario.fromDocument(data['user'] as Map); userAverageScore = await _loadAverageScore(user!.id); authStatus = AuthStatus.authenticated; notifyListeners(); _navigateAfterAuth(); } catch (e) { authStatus = AuthStatus.notAuthenticated; notifyListeners(); NotificationsService.showSnackBarError('Usuario o contraseña incorrectos'); } } Future register(String email, String password, String name) async { try { final data = await _api.post('/auth/register', { 'email': email, 'password': password, 'name': name.trim(), }); await _api.saveToken(data['access_token'] as String); user = Usuario.fromDocument(data['user'] as Map); authStatus = AuthStatus.authenticated; notifyListeners(); _navigateAfterAuth(); } catch (e) { authStatus = AuthStatus.notAuthenticated; notifyListeners(); NotificationsService.showSnackBarError('Email ya registrado'); } } Future verifyPhoneNumber(String phoneNumber) async { try { await _api.post('/auth/send-otp', {'phone': phoneNumber}); } catch (e) { NotificationsService.showSnackBarError('Error al enviar código SMS'); rethrow; } } Future signInWithOTP(String phoneNumber, String smsCode) async { try { final data = await _api.post('/auth/phone', {'phone': phoneNumber, 'code': smsCode}); await _api.saveToken(data['access_token'] as String); user = Usuario.fromDocument(data['user'] as Map); userAverageScore = await _loadAverageScore(user!.id); authStatus = AuthStatus.authenticated; notifyListeners(); // Usuario nuevo: el backend usa el teléfono como nombre por defecto final name = user!.name.trim(); final isNewUser = name.isEmpty || name == phoneNumber || name == phoneNumber.replaceAll('+57', ''); if (isNewUser) { NavigationService.replaceTo(Flurorouter.setupNameRoute); } else { NavigationService.replaceTo(Flurorouter.dashboardRoute); } } catch (e) { authStatus = AuthStatus.notAuthenticated; notifyListeners(); NotificationsService.showSnackBarError('Código incorrecto o expirado'); } } Future updateName(String name) async { try { await _api.patch('/users/me', {'name': name.trim()}); user = await _fetchMe(); notifyListeners(); } catch (_) { NotificationsService.showSnackBarError('Error al guardar el nombre'); rethrow; } } Future updateCity(String city) async { try { await _api.patch('/users/me', {'city': city.trim()}); user = await _fetchMe(); notifyListeners(); } catch (_) { NotificationsService.showSnackBarError('Error al guardar la ciudad'); rethrow; } } Future verifyPhoneNumberForLink(String phoneNumber) async { try { await _api.post('/auth/send-otp', {'phone': phoneNumber}); } catch (e) { NotificationsService.showSnackBarError('Error al enviar código SMS'); rethrow; } } Future linkPhoneWithOTP(String phoneNumber, String smsCode) async { try { await _api.post('/auth/verify-phone', {'phone': phoneNumber, 'code': smsCode}); user = await _fetchMe(); NotificationsService.showSnackbar('Número vinculado exitosamente'); authStatus = AuthStatus.authenticated; notifyListeners(); NavigationService.replaceTo(Flurorouter.profileRoute); } catch (e) { NotificationsService.showSnackBarError('Código incorrecto o expirado'); } } Future addEmailAndPassword(String email, String password) async { try { await _api.post('/auth/link-email', {'email': email, 'password': password}); user = await _fetchMe(); notifyListeners(); NotificationsService.showSnackbar('Email y contraseña añadidos exitosamente'); NavigationService.replaceTo(Flurorouter.profileRoute); } catch (e) { NotificationsService.showSnackBarError('Error al añadir email'); } } Future linkEmailWithOtp(String email, String password, String code) async { await _api.post('/auth/link-email-otp', { 'email': email, 'password': password, 'code': code, }); user = await _fetchMe(); notifyListeners(); NotificationsService.showSnackbar('Correo vinculado exitosamente'); } Future isAuthenticated() async { final token = await _api.getToken(); if (token == null) { authStatus = AuthStatus.notAuthenticated; notifyListeners(); _redirectToPhoneLogin(); return false; } try { final data = await _api.get('/auth/me'); user = Usuario.fromDocument(data as Map); userAverageScore = await _loadAverageScore(user!.id); authStatus = AuthStatus.authenticated; notifyListeners(); return true; } catch (e) { await _api.deleteToken(); authStatus = AuthStatus.notAuthenticated; notifyListeners(); _redirectToPhoneLogin(); return false; } } void _redirectToPhoneLogin() { SchedulerBinding.instance.addPostFrameCallback((_) { NavigationService.replaceTo(Flurorouter.phoneLoginRoute); }); } Future logout() async { await _api.deleteToken(); authStatus = AuthStatus.notAuthenticated; user = null; notifyListeners(); final ctx = NavigationService.navigatorKey.currentContext!; Provider.of(ctx, listen: false).logout(); Provider.of(ctx, listen: false).logout(); NavigationService.replaceTo(Flurorouter.phoneLoginRoute); } void refreshUser() => isAuthenticated(); Future _fetchMe() async { final data = await _api.get('/auth/me'); return Usuario.fromDocument(data as Map); } Future _loadAverageScore(String userId) async { try { final data = await _api.get('/comments/reputation/$userId'); final rep = data as Map; return (rep['average'] as num?)?.toDouble() ?? 0.0; } catch (_) { return 0.0; } } }