import 'dart:convert'; import '../constants/api_constants.dart'; import '../models/invitation_models.dart'; import 'http_service.dart'; import 'auth_service.dart'; import 'cache_service.dart'; class InvitationsService { static bool _pollingStarted = false; /// Get all invitations with caching - returns cached data if available and fresh static Future> getAllInvitations({ bool forceRefresh = false, }) async { // Return cached data if available and not forcing refresh if (!forceRefresh) { final cached = CacheService.getCached( CacheService.invitationsAllKey, ); if (cached != null && !CacheService.isCacheExpired( CacheService.invitationsAllKey, CacheService.invitationsCacheDuration, )) { return { 'success': true, 'message': 'Loaded from cache', 'invitations': cached, }; } // Return stale data while fetching fresh data in background final stale = CacheService.getCachedStale( CacheService.invitationsAllKey, ); if (stale != null && !forceRefresh) { // Trigger background refresh _fetchAndCacheInvitations(); return { 'success': true, 'message': 'Loaded from cache (refreshing in background)', 'invitations': stale, }; } } // Fetch fresh data return await _fetchAndCacheInvitations(); } static Future> _fetchAndCacheInvitations([ bool fromPolling = false, ]) async { try { final response = await HttpService.get( ApiConstants.getAllInvitationsEndpoint, ); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); final invitationsResponse = InvitationsResponse.fromJson(responseData); if (invitationsResponse.status) { final invitationsData = invitationsResponse.data; // Only cache when not called from polling to prevent conflicts if (!fromPolling) { CacheService.setCached( CacheService.invitationsAllKey, invitationsData, ); } return { 'success': true, 'invitations': invitationsData, 'message': invitationsResponse.message ?? '', }; } else { return { 'success': false, 'message': invitationsResponse.message ?? 'Failed to fetch invitations', 'invitations': InvitationsData( created: [], accepted: [], available: [], ), }; } } else if (response.statusCode == 401 || response.statusCode == 403) { await AuthService.handleAuthenticationError(); return { 'success': false, 'message': 'Session expired. Please login again.', 'invitations': InvitationsData( created: [], accepted: [], available: [], ), }; } else { return { 'success': false, 'message': 'Server error (${response.statusCode})', 'invitations': InvitationsData( created: [], accepted: [], available: [], ), }; } } catch (e) { print('Error fetching invitations: $e'); return { 'success': false, 'message': 'Network error. Please check your connection.', 'invitations': InvitationsData( created: [], accepted: [], available: [], ), }; } } /// Start background polling for invitations static void startPolling() { _pollingStarted = true; CacheService.startPolling( CacheService.invitationsAllKey, () => _fetchAndCacheInvitations(true), // Mark as from polling CacheService.invitationsPollingInterval, CacheService.invitationsCacheDuration, ); } /// Stop background polling for invitations static void stopPolling() { CacheService.stopPolling(CacheService.invitationsAllKey); _pollingStarted = false; } /// Get invitations stream for real-time updates static Stream getInvitationsStream() { return CacheService.getStream( CacheService.invitationsAllKey, ); } /// Check if polling is active static bool get isPollingActive => _pollingStarted; /// Invalidate invitations cache (useful after creating/updating invitations) static void invalidateCache() { CacheService.clearCache(CacheService.invitationsAllKey); } static Future> acceptInvitation(int invitationId) async { try { final response = await HttpService.post( ApiConstants.acceptInvitationEndpoint, {'id': invitationId}, ); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); // Invalidate invitations cache since invitation status changed invalidateCache(); return { 'success': responseData['status'] ?? false, 'message': responseData['message'] ?? 'Request completed', }; } else if (response.statusCode == 401) { return { 'success': false, 'message': 'Session expired. Please login again.', }; } else if (response.statusCode == 403) { return { 'success': false, 'message': 'Access denied. Invalid credentials.', }; } else { return { 'success': false, 'message': 'Server error (${response.statusCode})', }; } } catch (e) { print('Error accepting invitation: $e'); return { 'success': false, 'message': 'Network error. Please check your connection.', }; } } static Future> createInvitation( Map invitationData, ) async { try { final response = await HttpService.post( ApiConstants.createInvitationEndpoint, invitationData, ); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); if (responseData['status'] == true) { // Invalidate invitations cache since new invitation was created invalidateCache(); return { 'success': true, 'data': responseData['data'], 'message': responseData['message'], }; } else { return { 'success': false, 'message': responseData['message'] ?? 'Failed to create invitation', }; } } else if (response.statusCode == 401) { return { 'success': false, 'message': 'Session expired. Please login again.', }; } else if (response.statusCode == 403) { return { 'success': false, 'message': 'Access denied. Invalid credentials.', }; } else { return { 'success': false, 'message': 'Server error (${response.statusCode})', }; } } catch (e) { print('Error creating invitation: $e'); return { 'success': false, 'message': 'Network error. Please check your connection.', }; } } static Future> getInvitationDetails( int invitationId, ) async { try { final response = await HttpService.get( '${ApiConstants.invitationsEndpoint}/get?id=$invitationId', ); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); if (responseData['status'] == true) { final invitationDetails = InvitationDetails.fromJson( responseData['data'], ); return {'success': true, 'data': invitationDetails}; } else { return { 'success': false, 'message': responseData['message'] ?? 'Failed to get invitation details', }; } } else if (response.statusCode == 401) { return { 'success': false, 'message': 'Session expired. Please login again.', }; } else if (response.statusCode == 403) { return { 'success': false, 'message': 'Access denied. Invalid credentials.', }; } else { return { 'success': false, 'message': 'Server error (${response.statusCode})', }; } } catch (e) { print('Error getting invitation details: $e'); return { 'success': false, 'message': 'Network error. Please check your connection.', }; } } static Future> cancelInvitation(int invitationId) async { try { final response = await HttpService.post( '${ApiConstants.invitationsEndpoint}/cancel', {'id': invitationId}, ); if (response.statusCode == 200) { final responseData = jsonDecode(response.body); return { 'success': responseData['status'] ?? false, 'message': responseData['message'] ?? 'Request completed', }; } else if (response.statusCode == 401) { return { 'success': false, 'message': 'Session expired. Please login again.', }; } else if (response.statusCode == 403) { return { 'success': false, 'message': 'Access denied. Invalid credentials.', }; } else { return { 'success': false, 'message': 'Server error (${response.statusCode})', }; } } catch (e) { print('Error canceling invitation: $e'); return { 'success': false, 'message': 'Network error. Please check your connection.', }; } } }