# Offline Handling and Background Processing

This document describes the offline handling and background processing features implemented in the Milton Health Coach React Native SDK.

## Overview

The SDK provides robust offline support that ensures user requests are never lost, even when the device is offline or has poor network connectivity. The system automatically queues requests when offline and processes them when the network is restored.

## Key Features

### 1. Automatic Offline Detection
- Real-time network state monitoring using `@react-native-community/netinfo`
- Automatic switching between online and offline modes
- Graceful handling of network interruptions

### 2. Persistent Request Queuing
- Requests are automatically queued when the device is offline
- Queue is persisted to device storage using `@react-native-async-storage/async-storage`
- Queue survives app restarts and crashes
- Configurable queue size limits with automatic cleanup of oldest requests

### 3. Intelligent Retry Logic
- Automatic retry of failed requests with exponential backoff
- Configurable retry attempts and delays
- Permanent failure handling after maximum retry attempts
- Network error detection and appropriate retry strategies

### 4. Battery Optimization
- Different polling intervals for foreground and background modes
- Automatic switch to push notification mode after polling timeout
- Reduced polling frequency when app is in background
- Smart timeout calculations to preserve battery life

### 5. Push Notification Fallback
- Seamless fallback to push notifications when polling times out
- Automatic coordination between polling and push notifications
- Battery-efficient waiting for push notifications
- Resume polling when app becomes active

## Configuration

### Basic Configuration

```javascript
const client = new MiltonAsyncClient({
  baseUrl: 'https://api.milton.com',
  apiKey: 'your-api-key',
  
  // Offline handling configuration
  offlineConfig: {
    enableOfflineQueue: true,    // Enable offline request queuing
    maxQueueSize: 50,           // Maximum requests to queue
    retryAttempts: 3,           // Retry attempts for failed requests
    retryDelay: 5000,           // Delay between retries (ms)
    storageKey: 'milton_queue'  // AsyncStorage key for persistence
  },
  
  // Battery optimization configuration
  pollingConfig: {
    intervals: [1, 2, 4, 8, 15, 30],        // Foreground intervals (seconds)
    backgroundIntervals: [30, 60, 120, 300], // Background intervals (seconds)
    maxAttempts: 6,                          // Maximum polling attempts
    batteryOptimized: true                   // Enable battery optimization
  }
});
```

### Advanced Configuration

```javascript
const client = new MiltonAsyncClient({
  baseUrl: 'https://api.milton.com',
  apiKey: 'your-api-key',
  
  offlineConfig: {
    enableOfflineQueue: true,
    maxQueueSize: 100,          // Larger queue for heavy usage
    retryAttempts: 5,           // More retry attempts
    retryDelay: 3000,           // Faster retry for better UX
    storageKey: 'custom_queue'  // Custom storage key
  },
  
  pollingConfig: {
    intervals: [0.5, 1, 2, 5, 10],          // Faster initial polling
    backgroundIntervals: [60, 300, 600],     // Longer background intervals
    maxAttempts: 8,                          // More attempts before fallback
    batteryOptimized: true,
    timeoutMs: 60000                         // 1 minute timeout
  }
});
```

## Usage Examples

### Basic Offline Usage

```javascript
// Submit request - automatically handles offline scenarios
const response = await client.submitUserMessage({
  orgId: 123,
  userId: 456,
  question: "Log my breakfast"
}, {
  onProgress: (status) => {
    switch (status.status) {
      case 'queued_offline':
        console.log('Request queued for offline processing');
        showNotification('Request saved - will process when online');
        break;
      case 'processing':
        console.log('Request is being processed');
        break;
      case 'waiting_for_push':
        console.log('Waiting for push notification');
        break;
    }
  },
  onComplete: (result) => {
    console.log('Request completed:', result);
    showNotification('Analysis complete!');
  },
  onError: (error) => {
    console.error('Request failed:', error);
    if (error.message.includes('offline')) {
      showNotification('Please check your internet connection');
    }
  }
});
```

### Monitoring Offline Queue

```javascript
// Check queue status
const status = client.getOfflineQueueStatus();
console.log(`Queue: ${status.queueLength} items`);
console.log(`Online: ${status.isOnline}`);
console.log(`Background: ${status.isInBackground}`);
console.log(`Active polling: ${status.activePollingRequests}`);

// Display queue status to user
if (status.queueLength > 0) {
  showBanner(`${status.queueLength} requests queued for processing`);
}
```

### Manual Queue Management

```javascript
// Clear offline queue (useful for logout or reset)
await client.clearOfflineQueue();
console.log('Offline queue cleared');

// Force process queue (useful for testing)
if (client.isOnline) {
  await client.processOfflineQueue();
  console.log('Offline queue processed');
}
```

## Offline Behavior Patterns

### Network State Transitions

#### Going Offline
1. Network state changes to offline
2. Current polling requests are paused
3. New requests are automatically queued
4. User receives immediate feedback about offline status

#### Coming Online
1. Network state changes to online
2. Queued requests are automatically processed
3. Active polling resumes for existing requests
4. User receives notifications as requests complete

### App State Transitions

#### App Goes to Background
1. Polling intervals switch to battery-optimized mode
2. Longer intervals between polling attempts
3. Faster switch to push notification mode
4. Reduced network activity to preserve battery

#### App Becomes Active
1. Polling resumes with normal intervals
2. Offline queue is processed if network is available
3. Push notification mode switches back to polling
4. Full functionality restored

## Error Handling

### Network Errors
- Automatic detection of network-related errors
- Requests are queued for retry when network is restored
- User feedback about network issues
- Graceful degradation of functionality

### Storage Errors
- Fallback behavior when AsyncStorage is unavailable
- Error logging for debugging
- Continued operation without persistence

### API Errors
- Distinction between temporary and permanent failures
- Retry logic for temporary failures (5xx errors)
- Immediate failure for client errors (4xx errors)
- User feedback for different error types

## Performance Considerations

### Memory Usage
- Queue size limits prevent excessive memory usage
- Automatic cleanup of old requests
- Efficient data structures for queue management

### Battery Life
- Intelligent polling intervals based on app state
- Automatic switch to push notifications
- Reduced network activity in background mode
- Configurable timeouts and intervals

### Network Usage
- Exponential backoff reduces network load
- Batch processing of queued requests
- Efficient retry strategies
- Minimal overhead for status checks

## Debugging and Monitoring

### Console Logging
The SDK provides detailed console logging for debugging:

```javascript
// Enable debug logging (automatically enabled in development)
console.log('Milton SDK: Network state changed to offline');
console.log('Milton SDK: Added request to offline queue (5 items)');
console.log('Milton SDK: Processing offline queue');
console.log('Milton SDK: Successfully processed offline request abc123');
console.log('Milton SDK: Switching to battery-optimized polling');
console.log('Milton SDK: Polling timeout, waiting for push notification');
```

### Queue Status Monitoring
```javascript
// Monitor queue status in real-time
setInterval(() => {
  const status = client.getOfflineQueueStatus();
  updateUI({
    queueLength: status.queueLength,
    isOnline: status.isOnline,
    activeRequests: status.activePollingRequests
  });
}, 5000);
```

### Error Tracking
```javascript
const client = new MiltonAsyncClient({
  // ... config
}, {
  onError: (error, context) => {
    // Send to error tracking service
    errorTracker.captureException(error, {
      context: context,
      queueStatus: client.getOfflineQueueStatus()
    });
  }
});
```

## Best Practices

### 1. User Feedback
- Always provide feedback when requests are queued offline
- Show queue status in the UI
- Notify users when requests complete
- Handle errors gracefully with user-friendly messages

### 2. Queue Management
- Set appropriate queue size limits based on your use case
- Clear queue on user logout or app reset
- Monitor queue size and alert users if it grows too large

### 3. Battery Optimization
- Enable battery optimization for production apps
- Use appropriate polling intervals for your use case
- Consider push notifications for time-sensitive updates

### 4. Error Handling
- Implement comprehensive error handling
- Provide retry options for failed requests
- Log errors for debugging and monitoring

### 5. Testing
- Test offline scenarios thoroughly
- Verify queue persistence across app restarts
- Test battery optimization in background mode
- Validate push notification fallback behavior

## Troubleshooting

### Common Issues

**Requests not queuing when offline:**
- Verify `enableOfflineQueue` is set to `true`
- Check that `@react-native-community/netinfo` is properly installed
- Ensure AsyncStorage permissions are granted

**Queue not persisting across app restarts:**
- Verify `@react-native-async-storage/async-storage` is properly installed
- Check AsyncStorage permissions
- Ensure `storageKey` is unique and valid

**Battery drain in background:**
- Enable `batteryOptimized` in polling config
- Use longer `backgroundIntervals`
- Reduce `maxAttempts` for background mode

**Push notifications not working:**
- Verify Firebase configuration
- Check FCM token generation
- Ensure push notification permissions are granted
- Test with Firebase Console

### Debug Steps

1. **Check network state:**
   ```javascript
   console.log('Network state:', client.isOnline);
   ```

2. **Verify queue status:**
   ```javascript
   console.log('Queue status:', client.getOfflineQueueStatus());
   ```

3. **Test offline mode:**
   ```javascript
   // Simulate offline mode
   client.isOnline = false;
   // Submit request and verify it's queued
   ```

4. **Monitor console logs:**
   - Look for "Milton SDK:" prefixed messages
   - Check for error messages and warnings
   - Verify queue operations are logged

## Migration Guide

### From Basic SDK to Offline-Enabled SDK

**Before:**
```javascript
const client = new MiltonAsyncClient({
  baseUrl: 'https://api.milton.com',
  apiKey: 'your-api-key'
});

// Basic usage without offline handling
const response = await client.submitUserMessage(request);
```

**After:**
```javascript
const client = new MiltonAsyncClient({
  baseUrl: 'https://api.milton.com',
  apiKey: 'your-api-key',
  offlineConfig: {
    enableOfflineQueue: true,
    maxQueueSize: 50,
    retryAttempts: 3
  }
});

// Enhanced usage with offline handling
const response = await client.submitUserMessage(request, {
  onProgress: (status) => {
    if (status.status === 'queued_offline') {
      showOfflineMessage();
    }
  },
  onComplete: (result) => {
    hideOfflineMessage();
    showResult(result);
  }
});
```

### Required Dependencies

Add these dependencies to your project:

```bash
npm install @react-native-async-storage/async-storage @react-native-community/netinfo
```

Follow the installation guides for each dependency:
- [AsyncStorage Installation](https://react-native-async-storage.github.io/async-storage/docs/install/)
- [NetInfo Installation](https://github.com/react-native-netinfo/react-native-netinfo#getting-started)

## API Reference

### Configuration Options

#### OfflineConfig
```typescript
interface OfflineConfig {
  enableOfflineQueue: boolean;    // Enable offline request queuing
  maxQueueSize: number;          // Maximum requests to queue
  retryAttempts: number;         // Retry attempts for failed requests
  retryDelay: number;            // Delay between retries (ms)
  storageKey: string;            // AsyncStorage key for persistence
}
```

#### PollingConfig (Battery Optimization)
```typescript
interface PollingConfig {
  intervals: number[];           // Foreground polling intervals (seconds)
  backgroundIntervals: number[]; // Background polling intervals (seconds)
  maxAttempts: number;          // Maximum polling attempts
  batteryOptimized: boolean;    // Enable battery optimization
  timeoutMs: number;            // Request timeout (ms)
}
```

### Methods

#### getOfflineQueueStatus()
```typescript
getOfflineQueueStatus(): {
  queueLength: number;
  isOnline: boolean;
  isInBackground: boolean;
  activePollingRequests: number;
}
```

#### clearOfflineQueue()
```typescript
clearOfflineQueue(): Promise<void>
```

### Events

#### Progress Status Types
- `queued_offline`: Request queued for offline processing
- `processing`: Request is being processed on server
- `waiting_for_push`: Polling timeout, waiting for push notification
- `completed`: Request completed successfully
- `failed`: Request failed permanently
- `cancelled`: Request was cancelled

## Conclusion

The offline handling and background processing features provide a robust foundation for building resilient mobile applications. By automatically handling network interruptions, optimizing battery usage, and providing seamless user experiences, the SDK ensures that users can continue to interact with your app regardless of network conditions.

The combination of intelligent queuing, retry logic, battery optimization, and push notification fallback creates a comprehensive solution that handles the complexities of mobile network environments while maintaining excellent user experience and device performance.