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<String, Group> _groupCache = {};

  // Get current user ID
  String? get currentUserId => _supabase.auth.currentUser?.id;

  // Load all groups that the current user is a member of
  Future<List<Group>> 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<Group> 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<String, dynamic>;
        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<List<Group>> _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<void> _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<Group?> 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<String, dynamic>.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<bool> 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<bool> 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<bool> 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<List<Group>> getPublicGroups() async {
    try {
      final response = await _supabase
          .from('groups')
          .select('*, group_members(count)')
          .eq('is_public', true)
          .order('created_at');

      final List<Group> groups = [];

      for (final item in response) {
        final memberCount = item['group_members']?[0]?['count'] ?? 0;
        final groupData = Map<String, dynamic>.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<String> 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<bool> isGroupAdmin(String groupId) async {
    final role = await getUserRole(groupId);
    return role == 'admin';
  }

  // Check if user has moderator permissions
  Future<bool> isGroupModerator(String groupId) async {
    final role = await getUserRole(groupId);
    return role == 'admin' || role == 'moderator';
  }
}
