import 'package:dio/dio.dart'; import 'package:shared_preferences/shared_preferences.dart'; class ApiService { // static const String baseUrl = 'http://localhost:3000/api'; static const String baseUrl = 'https://chitfund.deepteklabs.com/api'; static const String tokenKey = 'auth_token'; late Dio _dio; ApiService() { _dio = Dio(BaseOptions( baseUrl: baseUrl, connectTimeout: const Duration(seconds: 30), receiveTimeout: const Duration(seconds: 30), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, )); // Add interceptor to include auth token _dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) async { final token = await _getToken(); if (token != null) { options.headers['Authorization'] = 'Bearer $token'; } handler.next(options); }, onError: (error, handler) { if (error.response?.statusCode == 401) { // Token expired or invalid _clearToken(); } handler.next(error); }, )); } // Token management Future _getToken() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString(tokenKey); } Future _saveToken(String token) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(tokenKey, token); } Future _clearToken() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove(tokenKey); } // Authentication APIs Future> signup(String mobileNumber, String fullName, String password, {String? email, String? address, String? emergencyContact}) async { try { final data = { 'mobile_number': mobileNumber, 'full_name': fullName, 'password': password, }; if (email != null && email.isNotEmpty) data['email'] = email; if (address != null && address.isNotEmpty) data['address'] = address; if (emergencyContact != null && emergencyContact.isNotEmpty) data['emergency_contact'] = emergencyContact; final response = await _dio.post('/auth/signup', data: data); if (response.data['success']) { await _saveToken(response.data['data']['token']); } return response.data; } on DioException catch (e) { return _handleError(e); } } Future> login(String mobileNumber, String password) async { try { final response = await _dio.post('/auth/login', data: { 'mobile_number': mobileNumber, 'password': password, }); if (response.data['success']) { await _saveToken(response.data['data']['token']); } return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getProfile() async { try { final response = await _dio.get('/auth/profile'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> updateProfile(Map data) async { try { final response = await _dio.put('/auth/profile', data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> changePassword(String currentPassword, String newPassword) async { try { final response = await _dio.put('/auth/change-password', data: { 'current_password': currentPassword, 'new_password': newPassword, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> createMember(String mobileNumber, String fullName, {String? email, String? address, String? emergencyContact}) async { try { final data = { 'mobile_number': mobileNumber, 'full_name': fullName, }; if (email != null && email.isNotEmpty) data['email'] = email; if (address != null && address.isNotEmpty) data['address'] = address; if (emergencyContact != null && emergencyContact.isNotEmpty) data['emergency_contact'] = emergencyContact; final response = await _dio.post('/auth/create-member', data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } // Chit Group APIs Future> createChitGroup(Map data) async { try { final response = await _dio.post('/chit-groups', data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getManagerChitGroups({String? status, int page = 1, int limit = 10}) async { try { final response = await _dio.get('/chit-groups/manager', queryParameters: { if (status != null) 'status': status, 'page': page, 'limit': limit, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getMemberChitGroups({String? status, int page = 1, int limit = 10}) async { try { final response = await _dio.get('/chit-groups/member', queryParameters: { if (status != null) 'status': status, 'page': page, 'limit': limit, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getChitGroupDetails(String groupId) async { try { final response = await _dio.get('/chit-groups/$groupId'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> updateChitGroup(String groupId, Map data) async { try { final response = await _dio.put('/chit-groups/$groupId', data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> deleteChitGroup(String groupId) async { try { final response = await _dio.delete('/chit-groups/$groupId'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> startChitGroup(String groupId) async { try { final response = await _dio.post('/chit-groups/$groupId/start'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getChitGroupStats(String groupId) async { try { final response = await _dio.get('/chit-groups/$groupId/stats'); return response.data; } on DioException catch (e) { return _handleError(e); } } // Member Management APIs Future> addMemberToGroup(String groupId, Map memberData) async { try { final response = await _dio.post('/members/$groupId/members', data: memberData); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> removeMemberFromGroup(String groupId, String memberId) async { try { final response = await _dio.delete('/members/$groupId/members/$memberId'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getAllUsers({String? search, int page = 1, int limit = 50}) async { try { final queryParams = { 'page': page, 'limit': limit, }; if (search != null && search.isNotEmpty) { queryParams['search'] = search; } final response = await _dio.get('/members/users', queryParameters: queryParams); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getAvailableUsersForGroup(String groupId) async { try { final response = await _dio.get('/members/users/available/$groupId'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getGroupMembers(String groupId, {String? status, int page = 1, int limit = 20}) async { try { final response = await _dio.get('/members/$groupId/members', queryParameters: { if (status != null) 'status': status, 'page': page, 'limit': limit, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getMemberDetails(String groupId, String memberId) async { try { final response = await _dio.get('/members/$groupId/members/$memberId'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> updateMemberStatus(String groupId, String memberId, String status) async { try { final response = await _dio.put('/members/$groupId/members/$memberId/status', data: { 'status': status, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getMemberPaymentSummary(String groupId, String memberId) async { try { final response = await _dio.get('/members/$groupId/members/$memberId/payment-summary'); return response.data; } on DioException catch (e) { return _handleError(e); } } // Payment Management APIs Future> recordPayment(Map data) async { try { final response = await _dio.post('/payments', data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getGroupPayments(String groupId, {String? status, int? month, int? year, int page = 1, int limit = 20}) async { try { final response = await _dio.get('/payments/group/$groupId', queryParameters: { if (status != null) 'status': status, if (month != null) 'month': month, if (year != null) 'year': year, 'page': page, 'limit': limit, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getMemberPayments(String groupId, String memberId, {String? status, int page = 1, int limit = 20}) async { try { final response = await _dio.get('/payments/group/$groupId/member/$memberId', queryParameters: { if (status != null) 'status': status, 'page': page, 'limit': limit, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> updatePaymentStatus(String paymentId, String status, {String? notes}) async { try { final response = await _dio.put('/payments/$paymentId/status', data: { 'status': status, if (notes != null) 'notes': notes, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getGroupPaymentSummary(String groupId) async { try { final response = await _dio.get('/payments/group/$groupId/summary'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getPendingPayments(String groupId) async { try { final response = await _dio.get('/payments/group/$groupId/pending'); return response.data; } on DioException catch (e) { return _handleError(e); } } // Monthly Draw APIs Future> createMonthlyDraw(Map data) async { try { final response = await _dio.post('/monthly-draws', data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getGroupMonthlyDraws(String groupId, {String? status, int page = 1, int limit = 20}) async { try { final response = await _dio.get('/monthly-draws/group/$groupId', queryParameters: { if (status != null) 'status': status, 'page': page, 'limit': limit, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getMonthlyDrawDetails(String drawId) async { try { final response = await _dio.get('/monthly-draws/$drawId'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> verifyDrawResult(String drawId, {String? clientSeed}) async { try { final response = await _dio.post('/monthly-draws/$drawId/verify', data: { if (clientSeed != null) 'client_seed': clientSeed, }); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getDrawStatistics(String groupId) async { try { final response = await _dio.get('/monthly-draws/group/$groupId/statistics'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> updateMonthlyDraw(String drawId, Map data) async { try { final response = await _dio.put('/monthly-draws/$drawId', data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> deleteMonthlyDraw(String drawId) async { try { final response = await _dio.delete('/monthly-draws/$drawId'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> getGroupFinancialData(String groupId) async { try { final response = await _dio.get('/chit-groups/$groupId/financial-data'); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> updateMemberDetails(String memberId, Map data) async { try { final response = await _dio.put('/auth/member/$memberId', data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } // Generic HTTP Methods Future> get(String path, {Map? queryParameters}) async { try { final response = await _dio.get(path, queryParameters: queryParameters); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> post(String path, Map data) async { try { final response = await _dio.post(path, data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> put(String path, Map data) async { try { final response = await _dio.put(path, data: data); return response.data; } on DioException catch (e) { return _handleError(e); } } Future> delete(String path) async { try { final response = await _dio.delete(path); return response.data; } on DioException catch (e) { return _handleError(e); } } // Logout Future logout() async { await _clearToken(); } // Error handling Map _handleError(DioException e) { if (e.response != null) { final responseData = e.response?.data; String message = 'Request failed'; if (responseData is Map) { message = responseData['message']?.toString() ?? 'Request failed'; } else if (responseData is String) { message = responseData; } return { 'success': false, 'message': message, 'statusCode': e.response?.statusCode, }; } else { return { 'success': false, 'message': 'Network error: ${e.message}', 'statusCode': 0, }; } } }