import 'package:flutter/material.dart';
import 'package:qpay/http/http.dart';
import 'package:qpay/models/api_response.dart';
import 'package:qpay/models/pageable_model.dart';
import 'package:qpay/screens/groups/models/create_group_from_file_response.dart';
import 'package:qpay/screens/groups/models/recipient_group_model.dart';

class GroupScreenModel {
  List<RecipientGroup> groups = [];
  List<RecipientGroupMember> members = [];
  PageableModel? membersPage;
  bool isLoading = false;
  bool isLoadingMore = false;
  String? errorMessage;
  int currentPage = 0;
  int totalPages = 0;
  int totalElements = 0;
  String searchQuery = '';
  bool selectMode = false;
  Set<String> selectedGroupIds = {};
}

class GroupController extends ChangeNotifier {
  final GroupScreenModel model = GroupScreenModel();
  final Http http = Http();
  BuildContext context;
  bool _disposed = false;

  GroupController(this.context);

  @override
  void dispose() {
    _disposed = true;
    super.dispose();
  }

  dynamic _unwrap(dynamic response) {
    if (response is Map && response.containsKey('body')) {
      return response['body'];
    }
    return response;
  }

  String buildQueryParameters(Map<String, String> params) {
    if (params.isEmpty) {
      return '';
    }

    String query = '';
    params.forEach((key, value) {
      query += '$key=$value&';
    });
    return query.substring(0, query.length - 1);
  }

  Future<ApiResponse<PageableModel>> listGroups({
    required String workspaceId,
    int page = 0,
    int size = 20,
    String? name,
  }) async {
    if (page == 0) {
      model.isLoading = true;
      model.groups = [];
      model.currentPage = 0;
    } else {
      model.isLoadingMore = true;
    }
    if (!_disposed) notifyListeners();

    try {
      final params = <String, String>{
        'workspaceId': workspaceId,
        'page': page.toString(),
        'size': size.toString(),
      };
      if (name != null && name.isNotEmpty) {
        params['name'] = name;
      }

      final raw = await http.get(
        '/recipient-groups?${buildQueryParameters(params)}',
      );
      final response = _unwrap(raw);
      final pageableModel = PageableModel.fromJson(
        response as Map<String, dynamic>,
      );

      final newGroups = pageableModel.content
          .map((e) => RecipientGroup.fromJson(e as Map<String, dynamic>))
          .toList();

      if (page == 0) {
        model.groups = newGroups;
      } else {
        model.groups.addAll(newGroups);
      }
      model.currentPage = pageableModel.number;
      model.totalPages = pageableModel.totalPages;
      model.totalElements = pageableModel.totalElements;
      model.isLoading = false;
      model.isLoadingMore = false;

      if (!_disposed) notifyListeners();
      return ApiResponse.success(pageableModel);
    } catch (e) {
      logger.e(e);
      model.errorMessage = e.toString();
      if (page == 0) {
        model.groups = [];
      }
      model.isLoading = false;
      model.isLoadingMore = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.failure('Failed to load groups');
    }
  }

  Future<void> searchGroups({required String workspaceId, String? name}) async {
    model.searchQuery = name ?? '';
    await listGroups(workspaceId: workspaceId, page: 0, name: name);
  }

  Future<void> loadNextPage({required String workspaceId}) async {
    if (model.isLoadingMore || model.currentPage + 1 >= model.totalPages) {
      return;
    }
    await listGroups(
      workspaceId: workspaceId,
      page: model.currentPage + 1,
      name: model.searchQuery.isNotEmpty ? model.searchQuery : null,
    );
  }

  Future<ApiResponse<List<RecipientGroupMember>>> listMembers(
    String groupId,
  ) async {
    model.isLoading = true;
    if (!_disposed) notifyListeners();
    try {
      final raw = await http.get(
        '/recipient-groups/members?recipientGroupId=$groupId',
      );
      final response = _unwrap(raw);
      model.membersPage = PageableModel.fromJson(response);
      final List<dynamic> content;
      if (response is List) {
        content = response;
      } else if (response is Map && response.containsKey('content')) {
        content = response['content'] as List<dynamic>;
      } else {
        content = [];
      }
      model.members = content
          .map((e) => RecipientGroupMember.fromJson(e as Map<String, dynamic>))
          .toList();
      model.isLoading = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.success(model.members);
    } catch (e, s) {
      logger.e(e);
      logger.e(s);
      model.errorMessage = e.toString();
      model.members = [];
      model.isLoading = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.failure('Failed to load members');
    }
  }

  Future<ApiResponse<RecipientGroup>> createGroup(
    CreateGroupRequest req,
  ) async {
    model.isLoading = true;
    if (!_disposed) notifyListeners();
    try {
      final raw = await http.post('/recipient-groups', req.toJson());
      final response = _unwrap(raw);
      final group = RecipientGroup.fromJson(response as Map<String, dynamic>);
      model.groups = [group, ...model.groups];
      model.isLoading = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.success(group);
    } catch (e) {
      logger.e(e);
      model.errorMessage = e.toString();
      model.isLoading = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.failure('Failed to create group');
    }
  }

  Future<void> deleteGroup({
    required String groupId,
    required String workspaceId,
  }) async {
    try {
      await http.delete(
        '/recipient-groups/delete/$groupId?workspaceId=$workspaceId',
      );
      model.groups.removeWhere((g) => g.id == groupId);
      model.selectedGroupIds.remove(groupId);
      if (!_disposed) notifyListeners();
    } catch (e) {
      logger.e(e);
      model.errorMessage = e.toString();
      if (!_disposed) notifyListeners();
    }
  }

  void toggleSelectMode() {
    model.selectMode = !model.selectMode;
    if (!model.selectMode) {
      model.selectedGroupIds.clear();
    }
    if (!_disposed) notifyListeners();
  }

  void toggleGroupSelection(String groupId) {
    if (model.selectedGroupIds.contains(groupId)) {
      model.selectedGroupIds.remove(groupId);
    } else {
      model.selectedGroupIds.add(groupId);
    }
    if (!_disposed) notifyListeners();
  }

  Future<void> removeMember({
    required String groupId,
    required String recipientId,
    required String workspaceId,
  }) async {
    try {
      await http.delete(
        '/recipient-groups/$groupId/members/$recipientId?workspaceId=$workspaceId',
      );
      model.members.removeWhere((m) => m.id == recipientId);
      if (!_disposed) notifyListeners();
    } catch (e) {
      logger.e(e);
      model.errorMessage = e.toString();
      if (!_disposed) notifyListeners();
    }
  }

  Future<void> deleteSelectedGroups({required String workspaceId}) async {
    final idsToDelete = List<String>.from(model.selectedGroupIds);
    model.selectMode = false;
    model.selectedGroupIds.clear();
    if (!_disposed) notifyListeners();

    for (final id in idsToDelete) {
      await deleteGroup(groupId: id, workspaceId: workspaceId);
    }
  }

  Future<ApiResponse<CreateGroupFromFileResponse>> createGroupFromFile({
    required String groupName,
    required String workspaceId,
    required String userId,
    String? description,
    required String currency,
    required List<int> fileBytes,
    required String fileName,
  }) async {
    model.isLoading = true;
    if (!_disposed) notifyListeners();

    try {
      final fields = <String, String>{
        'groupName': groupName,
        'workspaceId': workspaceId,
        'userId': userId,
        'currency': currency,
      };
      if (description != null && description.isNotEmpty) {
        fields['description'] = description;
      }

      final raw = await http.multipartPost(
        '/recipient-groups/create-from-file',
        fields,
        'file',
        fileBytes,
        fileName,
      );
      final response = _unwrap(raw);
      final result = CreateGroupFromFileResponse.fromJson(
        response as Map<String, dynamic>,
      );

      model.isLoading = false;
      if (!_disposed) notifyListeners();

      return ApiResponse.success(result);
    } catch (e) {
      logger.e(e);
      model.errorMessage = e.toString();
      model.isLoading = false;
      if (!_disposed) notifyListeners();
      return ApiResponse.failure('Failed to create group from file');
    }
  }
}
