//import 'package:supabase_flutter/supabase_flutter.dart';
import '../main.dart';

/// Data model for a collection.
class Collection {
  final String id;
  final String name;
  final String? description;
  final String ownerId;
  final DateTime createdAt;
  final String role; // 'owner' or 'member'
  final int itemCount;
  final int memberCount;

  Collection({
    required this.id,
    required this.name,
    this.description,
    required this.ownerId,
    required this.createdAt,
    required this.role,
    this.itemCount = 0,
    this.memberCount = 1,
  });

  bool get isOwner => role == 'owner';
  bool get isMember => role == 'member';
  bool get isViewer => role == 'viewer';
  bool get canModifyCars => isOwner || isMember;
}

/// Member of a collection.
class CollectionMember {
  final String id;
  final String userId;
  final String email;
  final String role;
  final DateTime joinedAt;

  CollectionMember({
    required this.id,
    required this.userId,
    required this.email,
    required this.role,
    required this.joinedAt,
  });

  bool get isOwner => role == 'owner';
  bool get isViewer => role == 'viewer';
}

/// Service for managing collections and membership.
class CollectionService {
  CollectionService._();

  /// Ensures the current user has at least one collection membership.
  /// Creates a default collection on first login.
  static Future<String?> ensureDefaultCollection() async {
    final userId = supabase.auth.currentUser?.id;
    if (userId == null) return null;

    final existing = await supabase
        .from('collection_members')
        .select('collection_id')
        .eq('user_id', userId)
        .limit(1);

    if (existing.isNotEmpty) {
      return existing.first['collection_id'] as String;
    }

    final created = await create(
      name: 'My Garage',
      description: 'Your default collection',
    );

    return created.id;
  }

  /// Fetch all collections the current user is a member of,
  /// including item count and member count.
  static Future<List<Collection>> getMyCollections() async {
    final userId = supabase.auth.currentUser!.id;

    // Get memberships with collection data.
    final memberships = await supabase
        .from('collection_members')
        .select('role, collections(id, name, description, owner_id, created_at)')
        .eq('user_id', userId);

    // If the user has no memberships, return early.
    if (memberships.isEmpty) {
      return <Collection>[];
    }

    // Collect all distinct collection IDs from memberships.
    final collectionIds = <String>{};
    for (final m in memberships) {
      final c = m['collections'] as Map<String, dynamic>;
      final collectionId = c['id'] as String;
      collectionIds.add(collectionId);
    }

    final collectionIdList = collectionIds.toList();

    // Fetch all items for these collections in a single query and count them in memory.
    final items = await supabase
        .from('hotwheels')
        .select('id, collection_id')
        .inFilter('collection_id', collectionIdList);

    final itemCounts = <String, int>{};
    for (final item in items) {
      final collectionId = item['collection_id'] as String;
      itemCounts[collectionId] = (itemCounts[collectionId] ?? 0) + 1;
    }

    final memberCounts = <String, int>{};
    await Future.wait(collectionIdList.map((collectionId) async {
      try {
        final rows = await supabase.rpc('get_collection_members', params: {
          'p_collection_id': collectionId,
        });
        memberCounts[collectionId] = (rows as List).length;
      } catch (_) {
        // Keep fallback below when RPC fails.
      }
    }));

    // Fallback member count for collections where RPC did not return data.
    final unresolvedIds = collectionIdList
        .where((id) => !memberCounts.containsKey(id))
        .toList(growable: false);
    if (unresolvedIds.isNotEmpty) {
      final members = await supabase
          .from('collection_members')
          .select('id, collection_id')
          .inFilter('collection_id', unresolvedIds);

      for (final member in members) {
        final collectionId = member['collection_id'] as String;
        memberCounts[collectionId] = (memberCounts[collectionId] ?? 0) + 1;
      }
    }

    final collections = <Collection>[];

    for (final m in memberships) {
      final c = m['collections'] as Map<String, dynamic>;
      final collectionId = c['id'] as String;

      collections.add(Collection(
        id: collectionId,
        name: c['name'] as String,
        description: c['description'] as String?,
        ownerId: c['owner_id'] as String,
        createdAt: DateTime.parse(c['created_at'] as String),
        role: m['role'] as String,
        itemCount: itemCounts[collectionId] ?? 0,
        memberCount: memberCounts[collectionId] ?? 1,
      ));
    }

    // Sort: owned first, then by name.
    collections.sort((a, b) {
      if (a.isOwner && !b.isOwner) return -1;
      if (!a.isOwner && b.isOwner) return 1;
      return a.name.compareTo(b.name);
    });

    return collections;
  }

  /// Create a new collection. The caller is automatically added as owner.
  static Future<Collection> create({
    required String name,
    String? description,
  }) async {
    final userId = supabase.auth.currentUser!.id;

    final row = await supabase
        .from('collections')
        .insert({
          'name': name,
          'owner_id': userId,
          if (description != null && description.isNotEmpty)
            'description': description,
        })
        .select()
        .single();

    // Add owner as a member.
    await supabase.from('collection_members').insert({
      'collection_id': row['id'],
      'user_id': userId,
      'role': 'owner',
    });

    return Collection(
      id: row['id'] as String,
      name: row['name'] as String,
      description: row['description'] as String?,
      ownerId: userId,
      createdAt: DateTime.parse(row['created_at'] as String),
      role: 'owner',
      itemCount: 0,
      memberCount: 1,
    );
  }

  /// Update a collection's name/description. Owner only.
  static Future<void> update({
    required String collectionId,
    required String name,
    String? description,
  }) async {
    final userId = supabase.auth.currentUser!.id;

    final collection = await supabase
        .from('collections')
        .select('owner_id')
        .eq('id', collectionId)
        .maybeSingle();

    if (collection == null) {
      throw Exception('Collection not found.');
    }
    if (collection['owner_id'] != userId) {
      throw Exception('Only the collection owner can perform this action.');
    }

    await supabase.from('collections').update({
      'name': name,
      if (description != null && description.isNotEmpty)
        'description': description,
    }).eq('id', collectionId);
  }

  /// Delete a collection. Owner only. Cascade deletes members & items.
  static Future<void> delete(String collectionId) async {
    final userId = supabase.auth.currentUser!.id;

    final collection = await supabase
        .from('collections')
        .select('owner_id')
        .eq('id', collectionId)
        .maybeSingle();

    if (collection == null) {
      throw Exception('Collection not found.');
    }
    if (collection['owner_id'] != userId) {
      throw Exception('Only the collection owner can perform this action.');
    }

    await supabase.from('collections').delete().eq('id', collectionId);
  }

  /// Get members of a collection (with emails via RPC).
  static Future<List<CollectionMember>> getMembers(
      String collectionId) async {
    final rows = await supabase.rpc('get_collection_members', params: {
      'p_collection_id': collectionId,
    });

    final members = <CollectionMember>[];
    for (final r in rows) {
      members.add(CollectionMember(
        id: r['id'] as String,
        userId: r['user_id'] as String,
        email: r['email'] as String? ?? 'unknown',
        role: r['role'] as String,
        joinedAt: DateTime.parse(r['created_at'] as String),
      ));
    }

    return members;
  }

  /// Invite a user by email. Looks up auth.users via an RPC function,
  /// then inserts a collection_members row.
  static Future<void> inviteByEmail({
    required String collectionId,
    required String email,
    String role = 'member',
  }) async {
    final normalizedRole = role.trim().toLowerCase();
    if (normalizedRole != 'member' && normalizedRole != 'viewer') {
      throw Exception('Unsupported role "$role".');
    }

    final currentUserId = supabase.auth.currentUser!.id;

    final collection = await supabase
        .from('collections')
        .select('owner_id')
        .eq('id', collectionId)
        .maybeSingle();

    if (collection == null) {
      throw Exception('Collection not found.');
    }
    if (collection['owner_id'] != currentUserId) {
      throw Exception('Only the collection owner can invite members.');
    }

    // Call an RPC to look up the user ID by email.
    final result = await supabase.rpc('get_user_id_by_email', params: {
      'lookup_email': email.trim().toLowerCase(),
    });

    if (result == null || (result is List && result.isEmpty)) {
      throw Exception(
          'No user found with that email. They must create an account first.');
    }

    final userId = result is List ? result.first['id'] as String : result as String;

    if (userId == currentUserId) {
      throw Exception('You are already in this collection.');
    }

    // Check if already a member.
    final existing = await supabase
        .from('collection_members')
        .select('id')
        .eq('collection_id', collectionId)
        .eq('user_id', userId)
        .maybeSingle();

    if (existing != null) {
      throw Exception('This user is already a member of this collection.');
    }

    try {
      await supabase.from('collection_members').insert({
        'collection_id': collectionId,
        'user_id': userId,
        'role': normalizedRole,
      });
    } catch (e) {
      final message = e.toString();
      if (normalizedRole == 'viewer' &&
          message.contains('collection_members_role_check')) {
        throw Exception(
          'Viewer role is not enabled in your database yet. Please apply the viewer-role migration first.',
        );
      }
      rethrow;
    }
  }

  /// Remove a member from a collection.
  static Future<void> removeMember({
    required String collectionId,
    required String memberUserId,
  }) async {
    final currentUserId = supabase.auth.currentUser!.id;

    final collection = await supabase
        .from('collections')
        .select('owner_id')
        .eq('id', collectionId)
        .maybeSingle();

    if (collection == null) {
      throw Exception('Collection not found.');
    }
    if (collection['owner_id'] != currentUserId) {
      throw Exception('Only the collection owner can remove members.');
    }

    if (memberUserId == collection['owner_id']) {
      throw Exception('Collection owner cannot be removed.');
    }

    final membersBefore = await getMembers(collectionId);
    final targetMembership =
      membersBefore.where((member) => member.userId == memberUserId);

    if (targetMembership.isEmpty) {
      throw Exception('Member not found in this collection.');
    }
    final target = targetMembership.first;
    if (target.role == 'owner') {
      throw Exception('Collection owner cannot be removed.');
    }

    await supabase
        .from('collection_members')
        .delete()
      .eq('collection_id', collectionId)
        .eq('user_id', memberUserId);

    final membersAfter = await getMembers(collectionId);
    final stillExists =
        membersAfter.any((member) => member.userId == memberUserId);
    if (stillExists) {
      throw Exception('Member removal did not persist. Please check RLS delete policy.');
    }
  }

  /// Leave a collection (for non-owners).
  static Future<void> leave(String collectionId) async {
    final userId = supabase.auth.currentUser!.id;

    final membership = await supabase
        .from('collection_members')
        .select('role')
        .eq('collection_id', collectionId)
        .eq('user_id', userId)
        .maybeSingle();

    if (membership == null) {
      throw Exception('You are not a member of this collection.');
    }
    if (membership['role'] == 'owner') {
      throw Exception('Owner cannot leave. Delete the collection instead.');
    }

    await supabase
        .from('collection_members')
        .delete()
        .eq('collection_id', collectionId)
        .eq('user_id', userId);
  }
}
