import 'package:supabase_flutter/supabase_flutter.dart'; import '../constants/app_constants.dart'; class SupabaseService { static SupabaseClient get _supabase => Supabase.instance.client; // Initialize Supabase static Future initialize() async { try { print('DEBUG: Inicializando Supabase...'); await Supabase.initialize( url: AppConstants.supabaseUrl, anonKey: AppConstants.supabaseAnonKey, ); print('DEBUG: Supabase inicializado com sucesso!'); } catch (e) { print('DEBUG: Erro ao inicializar Supabase: $e'); rethrow; } } // Get current user static User? get currentUser => _supabase.auth.currentUser; // Sign up with email and password static Future signUp({ required String email, required String password, required String name, }) async { try { final response = await _supabase.auth.signUp( email: email, password: password, data: {'name': name}, ); if (response.user != null) { // Criar usuário na tabela personalizada await _createUserInTable(response.user!); return response; } else { throw Exception('Falha ao criar usuário.'); } } catch (e) { throw Exception('Erro ao criar conta: $e'); } } // Sign in with email and password static Future signIn({ required String email, required String password, }) async { try { final response = await _supabase.auth.signInWithPassword( email: email, password: password, ); if (response.user != null) { // Verificar se usuário existe na tabela personalizada await _ensureUserInTable(response.user!); return response; } else { throw Exception('Falha ao fazer login.'); } } catch (e) { throw Exception('Erro ao fazer login: $e'); } } // Criar usuário na tabela personalizada static Future _createUserInTable(User user) async { try { await _supabase.from('user').insert({ 'id_user': user.id, 'user_nome': user.userMetadata?['name'] ?? 'Usuário', 'email': user.email, 'senha': '', // Não armazenamos senha, só usamos o Auth }); print('DEBUG: Usuário criado na tabela personalizada: ${user.id}'); } catch (e) { print('DEBUG: Erro ao criar usuário na tabela: $e'); // Não lançar exceção para não bloquear o login } } // Verificar se usuário existe na tabela personalizada static Future _ensureUserInTable(User user) async { try { final existingUser = await _supabase .from('user') .select('id_user') .eq('id_user', user.id) .maybeSingle(); if (existingUser == null) { // Criar usuário se não existir await _createUserInTable(user); } else { print('DEBUG: Usuário já existe na tabela personalizada: ${user.id}'); } } catch (e) { print('DEBUG: Erro ao verificar usuário na tabela: $e'); } } // Sign out static Future signOut() async { try { await _supabase.auth.signOut(); } catch (e) { throw Exception('Erro ao sair: $e'); } } // Reset password static Future resetPassword(String email) async { try { await _supabase.auth.resetPasswordForEmail(email); } catch (e) { throw Exception('Erro ao redefinir senha: $e'); } } // Update user profile static Future updateProfile({String? name, String? email}) async { try { final updates = {}; if (name != null) updates['name'] = name; final userAttributes = UserAttributes( data: updates.isNotEmpty ? updates : null, email: email, ); await _supabase.auth.updateUser(userAttributes); } catch (e) { throw Exception('Erro ao atualizar perfil: $e'); } } // Test connection to Supabase static Future testConnection() async { try { final session = _supabase.auth.currentSession; return true; } catch (e) { return false; } } // Debug method to check user authentication static void debugAuthState() { final user = currentUser; final session = _supabase.auth.currentSession; print('DEBUG: User authenticated: ${user != null}'); print('DEBUG: User ID: ${user?.id}'); print('DEBUG: User ID type: ${user?.id.runtimeType}'); print('DEBUG: User email: ${user?.email}'); print('DEBUG: Session valid: ${session != null}'); print('DEBUG: Session expires at: ${session?.expiresAt}'); } // Listen to auth state changes static Stream get authStateChanges => _supabase.auth.onAuthStateChange; // Save a new run static Future saveRun({ required double distance, required double pace, }) async { try { // Debug authentication state debugAuthState(); final userId = currentUser?.id; if (userId == null) { throw Exception('Usuário não autenticado - userId é null'); } print('DEBUG: Tentando salvar corrida com userId: $userId'); print('DEBUG: Distance: $distance, Pace: $pace'); // Garantir que o usuário existe na tabela user antes de salvar await _ensureUserExists(userId); // Insert new run await _supabase.from('runs').insert({ 'id_user': userId, 'distance': distance, 'pace': pace, 'created_at': DateTime.now().toIso8601String(), }); print('DEBUG: Corrida salva com sucesso!'); // Update user stats await _updateUserStats(userId, distance, pace); } catch (e) { print('DEBUG: Erro completo: $e'); throw Exception('Erro ao salvar corrida: $e'); } } // Forçar criação do usuário na tabela se não existir static Future _ensureUserExists(String userId) async { try { final existingUser = await _supabase .from('user') .select('id_user') .eq('id_user', userId) .maybeSingle(); if (existingUser == null) { print('DEBUG: Usuário não encontrado, criando na tabela user...'); await _supabase.from('user').insert({ 'id_user': userId, 'user_nome': 'Usuário App', 'email': 'app@runvision.com', 'senha': '', }); print('DEBUG: Usuário criado com sucesso na tabela user!'); } else { print('DEBUG: Usuário já existe na tabela user'); } } catch (e) { print('DEBUG: Erro ao verificar/criar usuário: $e'); // Tentar criar mesmo assim try { await _supabase.from('user').insert({ 'id_user': userId, 'user_nome': 'Usuário App', 'email': 'app@runvision.com', 'senha': '', }); print('DEBUG: Usuário criado com sucesso (fallback)!'); } catch (e2) { print('DEBUG: Falha total ao criar usuário: $e2'); } } } // Update user statistics static Future _updateUserStats( String userId, double newDistance, double newPace, ) async { try { // Get current user stats final currentStats = await _supabase .from('user_stats') .select('best_pace, max_distance') .eq('id_user', userId) .maybeSingle(); if (currentStats == null) { // Create new user stats record await _supabase.from('user_stats').insert({ 'id_user': userId, 'best_pace': newPace, 'max_distance': newDistance, 'created_at': DateTime.now().toIso8601String(), }); } else { // Update if new records are better final updates = {}; if (currentStats['max_distance'] == null || newDistance > currentStats['max_distance']) { updates['max_distance'] = newDistance; } if (currentStats['best_pace'] == null || newPace < currentStats['best_pace']) { updates['best_pace'] = newPace; } if (updates.isNotEmpty) { await _supabase .from('user_stats') .update(updates) .maybeSingle(); // Removido o filtro por id_user } } } catch (e) { throw Exception('Erro ao atualizar estatísticas: $e'); } } // Get user statistics static Future?> getUserStats() async { try { final userId = currentUser?.id; if (userId == null) { throw Exception('Usuário não autenticado'); } return await _supabase .from('user_stats') .select('*') .eq('id_user', userId) .maybeSingle(); } catch (e) { throw Exception('Erro ao buscar estatísticas: $e'); } } // Get user runs history static Future>> getUserRuns({ int limit = 50, }) async { try { final userId = currentUser?.id; if (userId == null) { throw Exception('Usuário não autenticado'); } return await _supabase .from('runs') .select('*') .eq('id_user', userId) .order('created_at', ascending: false) .limit(limit); } catch (e) { throw Exception('Erro ao buscar histórico de corridas: $e'); } } }