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 GroupManagementService { final _supabase = Supabase.instance.client; // Get current user ID String? get currentUserId => _supabase.auth.currentUser?.id; // Check if the current user is an admin Future isUserAdmin() async { if (currentUserId == null) return false; try { final response = await _supabase .from('user_roles') .select('role') .eq('user_id', currentUserId!) .maybeSingle(); if (response == null) return false; return response['role'] == 'admin'; } catch (e) { print('[ERROR] Failed to check if user is admin: $e'); return false; } } // Get all groups (admin only) Future> getAllGroups() async { print('[DEBUG] Starting getAllGroups()'); final bool isAdmin = await isUserAdmin(); print('[DEBUG] isUserAdmin result: $isAdmin'); if (!isAdmin) { print('[ERROR] Unauthorized access to admin function'); return []; } try { print('[DEBUG] Fetching groups from database...'); final response = await _supabase .from('groups') .select('*, group_members(count)') .order('created_at'); print('[DEBUG] Raw response from groups query: $response'); if (response.isEmpty) { print('[DEBUG] No groups found in response'); return []; } final List groups = []; for (final item in response) { print('[DEBUG] Processing group: ${item['name']} (${item['id']})'); final memberCount = item['group_members']?[0]?['count'] ?? 0; final groupData = Map.from(item); groupData['member_count'] = memberCount; final group = Group.fromMap(groupData); groups.add(group); } print('[DEBUG] Returned ${groups.length} groups'); return groups; } catch (e) { print('[ERROR] Failed to load all groups: $e'); return []; } } // Create a new group (admin only) Future createGroup(Group group) async { if (!await isUserAdmin()) { print('[ERROR] Unauthorized access to admin function'); return null; } try { // Insert group dengan id dari group parameter final response = await _supabase .from('groups') .insert({ 'id': group.id, 'name': group.name, 'description': group.description, 'created_by': group.createdBy, 'created_at': group.createdAt.toIso8601String(), 'is_default': group.isDefault, 'is_public': group.isPublic, 'icon_url': group.iconUrl, }) .select('id') .single(); print('[INFO] Group created successfully: ${response['id']}'); // Ensure we use the ID from response in case it's different final createdGroupId = response['id'] as String; // Add creator as admin member final member = GroupMember( groupId: createdGroupId, userId: currentUserId!, role: 'admin', ); await _supabase.from('group_members').insert(member.toMap()); // Return group with proper ID return group.copyWith(id: createdGroupId); } catch (e) { print('[ERROR] Failed to create group: $e'); return null; } } // Update an existing group (admin only) Future updateGroup(Group group) async { if (!await isUserAdmin()) { print('[ERROR] Unauthorized access to admin function'); return false; } try { await _supabase.from('groups').update(group.toMap()).eq('id', group.id); return true; } catch (e) { print('[ERROR] Failed to update group: $e'); return false; } } // Delete a group (admin only) Future deleteGroup(String groupId) async { if (!await isUserAdmin()) { print('[ERROR] Unauthorized access to admin function'); return false; } try { // Check if this is the default group final response = await _supabase .from('groups') .select('is_default') .eq('id', groupId) .single(); if (response['is_default'] == true) { // Cannot delete default group return false; } // Delete group members first (due to foreign key constraints) await _supabase.from('group_members').delete().eq('group_id', groupId); // Delete the group await _supabase.from('groups').delete().eq('id', groupId); return true; } catch (e) { print('[ERROR] Failed to delete group: $e'); return false; } } // Get all members of a group (admin only) Future> getGroupMembers(String groupId) async { if (!await isUserAdmin()) { print('[ERROR] Unauthorized access to admin function'); return []; } try { final response = await _supabase .from('group_members') .select('*, profiles:user_id(username, avatar_url, email)') .eq('group_id', groupId) .eq('is_active', true) .order('joined_at'); final List members = []; for (final item in response) { final member = GroupMember.fromMap(item); final profile = item['profiles'] as Map?; members.add( GroupMemberDetail( member: member, username: profile?['username'] as String? ?? 'Unknown User', email: profile?['email'] as String?, avatarUrl: profile?['avatar_url'] as String?, ), ); } return members; } catch (e) { print('[ERROR] Failed to load group members: $e'); return []; } } // Remove a user from a group (admin only) Future removeGroupMember(String groupId, String userId) async { if (!await isUserAdmin()) { print('[ERROR] Unauthorized access to admin function'); return false; } try { // Mark as inactive instead of deleting await _supabase .from('group_members') .update({'is_active': false}) .eq('group_id', groupId) .eq('user_id', userId); return true; } catch (e) { print('[ERROR] Failed to remove group member: $e'); return false; } } // Change a member's role (admin only) Future changeGroupMemberRole( String groupId, String userId, String newRole, ) async { if (!await isUserAdmin()) { print('[ERROR] Unauthorized access to admin function'); return false; } // Validate role if (!['admin', 'moderator', 'member'].contains(newRole)) { print('[ERROR] Invalid role: $newRole'); return false; } try { await _supabase .from('group_members') .update({'role': newRole}) .eq('group_id', groupId) .eq('user_id', userId); return true; } catch (e) { print('[ERROR] Failed to change member role: $e'); return false; } } // Add all users to a default group (admin only) Future addAllUsersToDefaultGroup(String defaultGroupId) async { if (!await isUserAdmin()) { print('[ERROR] Unauthorized access to admin function'); return false; } try { // Cara langsung menggunakan RPC untuk menghindari masalah RLS final result = await _supabase.rpc( 'add_all_users_to_group', params: {'group_id_param': defaultGroupId}, ); print('[INFO] Added users to default group: $result'); return result == true; } catch (e) { print('[ERROR] Failed to add all users to default group: $e'); // Fallback jika RPC tidak tersedia try { // Get all user IDs final usersResponse = await _supabase .from('profiles') .select('user_id'); // Get existing members of the group final membersResponse = await _supabase .from('group_members') .select('user_id') .eq('group_id', defaultGroupId); final existingMemberIds = membersResponse.map((m) => m['user_id'] as String).toSet(); // Create members for users who aren't already in the group final List> newMembers = []; for (final user in usersResponse) { final userId = user['user_id'] as String; if (!existingMemberIds.contains(userId)) { newMembers.add( GroupMember(groupId: defaultGroupId, userId: userId).toMap(), ); } } if (newMembers.isNotEmpty) { await _supabase.from('group_members').insert(newMembers); } print( '[INFO] Added ${newMembers.length} users to default group (fallback method)', ); return true; } catch (fallbackError) { print('[ERROR] Fallback method also failed: $fallbackError'); return false; } } } // Create a new group (admin only) menggunakan RPC Future createGroupViaRPC({ required String name, required String description, required bool isPublic, required bool isDefault, String? iconUrl, }) async { if (currentUserId == null) { print('[ERROR] User not authenticated'); return null; } try { // Panggil fungsi RPC di database final response = await _supabase.rpc( 'create_group_with_creator', params: { 'name': name, 'description': description, 'created_by': currentUserId, 'is_public': isPublic, 'is_default': isDefault, 'icon_url': iconUrl, }, ); print('[INFO] Group created via RPC: $response'); if (response != null) { // Buat objek Group dari hasil final createdGroup = Group( id: response as String, name: name, description: description, createdBy: currentUserId!, isPublic: isPublic, isDefault: isDefault, iconUrl: iconUrl, ); return createdGroup; } return null; } catch (e) { print('[ERROR] Failed to create group via RPC: $e'); return null; } } } // Helper class for group member details class GroupMemberDetail { final GroupMember member; final String username; final String? email; final String? avatarUrl; GroupMemberDetail({ required this.member, required this.username, this.email, this.avatarUrl, }); }