import 'package:flutter/material.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<void> 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<String, dynamic>);
      userAverageScore = await _loadAverageScore(user!.id);
      authStatus = AuthStatus.authenticated;
      notifyListeners();
      _navigateAfterAuth();
    } catch (e) {
      authStatus = AuthStatus.notAuthenticated;
      notifyListeners();
      NotificationsService.showSnackBarError('Usuario o contraseña incorrectos');
    }
  }

  Future<void> 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<String, dynamic>);
      authStatus = AuthStatus.authenticated;
      notifyListeners();
      _navigateAfterAuth();
    } catch (e) {
      authStatus = AuthStatus.notAuthenticated;
      notifyListeners();
      NotificationsService.showSnackBarError('Email ya registrado');
    }
  }

  Future<void> 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<void> 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<String, dynamic>);
      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<void> 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<void> 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<void> 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<void> 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<void> 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<void> 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<bool> isAuthenticated() async {
    final token = await _api.getToken();
    if (token == null) {
      authStatus = AuthStatus.notAuthenticated;
      notifyListeners();
      return false;
    }
    try {
      final data = await _api.get('/auth/me');
      user = Usuario.fromDocument(data as Map<String, dynamic>);
      userAverageScore = await _loadAverageScore(user!.id);
      authStatus = AuthStatus.authenticated;
      notifyListeners();
      return true;
    } catch (e) {
      await _api.deleteToken();
      authStatus = AuthStatus.notAuthenticated;
      notifyListeners();
      return false;
    }
  }

  Future<void> logout() async {
    await _api.deleteToken();
    authStatus = AuthStatus.notAuthenticated;
    user = null;
    notifyListeners();

    final ctx = NavigationService.navigatorKey.currentContext!;
    Provider.of<ServicesProvider>(ctx, listen: false).logout();
    Provider.of<ProfessionalProvider>(ctx, listen: false).logout();

    NavigationService.replaceTo(Flurorouter.phoneLoginRoute);
  }

  void refreshUser() => isAuthenticated();

  Future<Usuario> _fetchMe() async {
    final data = await _api.get('/auth/me');
    return Usuario.fromDocument(data as Map<String, dynamic>);
  }

  Future<double> _loadAverageScore(String userId) async {
    try {
      final data = await _api.get('/comments/reputation/$userId');
      final rep = data as Map<String, dynamic>;
      return (rep['average'] as num?)?.toDouble() ?? 0.0;
    } catch (_) {
      return 0.0;
    }
  }
}
