import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:tugas_akhir_supabase/screens/community/models/group.dart'; import 'package:tugas_akhir_supabase/screens/community/models/group_member.dart'; class GroupService { final _supabase = Supabase.instance.client; // Cache final Map _groupCache = {}; // Get current user ID String? get currentUserId => _supabase.auth.currentUser?.id; // Load all groups that the current user is a member of Future> getUserGroups() async { if (currentUserId == null) { print('[ERROR] getUserGroups: currentUserId is null'); return []; } try { print( '[DEBUG] getUserGroups: Querying group_members for user: $currentUserId', ); // Join group_members with groups to get all groups for current user final response = await _supabase .from('group_members') .select('groups(*)') .eq('user_id', currentUserId!) .eq('is_active', true) .order('joined_at'); print('[DEBUG] getUserGroups: Raw response: $response'); if (response.isEmpty) { print( '[DEBUG] getUserGroups: No groups found in response, trying fallback', ); // Fallback: Try to get default group directly return await _getDefaultGroup(); } final List groups = []; for (final item in response) { if (item['groups'] == null) { print('[WARNING] getUserGroups: Null groups data in item: $item'); continue; } final groupData = item['groups'] as Map; print('[DEBUG] getUserGroups: Processing group: ${groupData['name']}'); final group = Group.fromMap(groupData); // Update cache _groupCache[group.id] = group; groups.add(group); } print('[INFO] getUserGroups: Found ${groups.length} groups for user'); if (groups.isEmpty) { // If no groups found via membership, try to get default group print( '[DEBUG] getUserGroups: No groups found via membership, trying to get default group', ); return await _getDefaultGroup(); } return groups; } catch (e) { print('[ERROR] Failed to load user groups: $e'); // Try fallback on error return await _getDefaultGroup(); } } // Fallback method to get at least the default group Future> _getDefaultGroup() async { try { print('[DEBUG] Trying to get default group directly'); final response = await _supabase .from('groups') .select('*') .eq('is_default', true) .limit(1); print('[DEBUG] Default group response: $response'); if (response.isNotEmpty) { final groupData = response[0]; final group = Group.fromMap(groupData); print('[INFO] Found default group: ${group.name}'); // Auto-join user to this group if needed if (currentUserId != null) { _joinGroupIfNotMember(group.id); } // Update cache _groupCache[group.id] = group; return [group]; } print('[WARNING] No default group found'); return []; } catch (e) { print('[ERROR] Failed to get default group: $e'); return []; } } // Utility to join user to group if not already a member Future _joinGroupIfNotMember(String groupId) async { try { final isMember = await isUserGroupMember(groupId); if (!isMember && currentUserId != null) { print('[INFO] Auto-joining user to group: $groupId'); final member = GroupMember(groupId: groupId, userId: currentUserId!); await _supabase.from('group_members').insert(member.toMap()); } } catch (e) { print('[ERROR] Failed to auto-join group: $e'); } } // Get details of a specific group Future getGroupDetails(String groupId) async { // Try cache first if (_groupCache.containsKey(groupId)) { return _groupCache[groupId]; } try { final response = await _supabase .from('groups') .select('*, group_members(count)') .eq('id', groupId) .single(); final memberCount = response['group_members']?[0]?['count'] ?? 0; final groupData = Map.from(response); groupData['member_count'] = memberCount; final group = Group.fromMap(groupData); // Update cache _groupCache[group.id] = group; return group; } catch (e) { print('[ERROR] Failed to get group details: $e'); return null; } } // Check if user is a member of a group Future isUserGroupMember(String groupId, {String? userId}) async { final targetUserId = userId ?? currentUserId; if (targetUserId == null) return false; try { final response = await _supabase .from('group_members') .select('id') .eq('group_id', groupId) .eq('user_id', targetUserId) .eq('is_active', true) .maybeSingle(); return response != null; } catch (e) { print('[ERROR] Failed to check group membership: $e'); return false; } } // Join a group Future joinGroup(String groupId) async { if (currentUserId == null) return false; // Check if already a member final isMember = await isUserGroupMember(groupId); if (isMember) return true; // Already a member try { // Create new group member final member = GroupMember(groupId: groupId, userId: currentUserId!); await _supabase.from('group_members').insert(member.toMap()); // Clear cache for this group to refresh member count _groupCache.remove(groupId); return true; } catch (e) { print('[ERROR] Failed to join group: $e'); return false; } } // Leave a group Future leaveGroup(String groupId) async { if (currentUserId == null) return false; try { // Check if this is the default group final group = await getGroupDetails(groupId); if (group?.isDefault == true) { // Can't leave default group return false; } // Mark as inactive instead of deleting await _supabase .from('group_members') .update({'is_active': false}) .eq('group_id', groupId) .eq('user_id', currentUserId!); // Clear cache for this group _groupCache.remove(groupId); return true; } catch (e) { print('[ERROR] Failed to leave group: $e'); return false; } } // Get all public groups Future> getPublicGroups() async { try { final response = await _supabase .from('groups') .select('*, group_members(count)') .eq('is_public', true) .order('created_at'); final List groups = []; for (final item in response) { final memberCount = item['group_members']?[0]?['count'] ?? 0; final groupData = Map.from(item); groupData['member_count'] = memberCount; final group = Group.fromMap(groupData); // Update cache _groupCache[group.id] = group; groups.add(group); } return groups; } catch (e) { print('[ERROR] Failed to load public groups: $e'); return []; } } // Get group member role for current user Future getUserRole(String groupId) async { if (currentUserId == null) return 'none'; try { final response = await _supabase .from('group_members') .select('role') .eq('group_id', groupId) .eq('user_id', currentUserId!) .eq('is_active', true) .maybeSingle(); if (response == null) return 'none'; return response['role'] as String? ?? 'member'; } catch (e) { print('[ERROR] Failed to get user role: $e'); return 'none'; } } // Check if user has admin permissions Future isGroupAdmin(String groupId) async { final role = await getUserRole(groupId); return role == 'admin'; } // Check if user has moderator permissions Future isGroupModerator(String groupId) async { final role = await getUserRole(groupId); return role == 'admin' || role == 'moderator'; } }