/**
 * API with Retry Logic
 * 
 * Enhanced API utility with exponential backoff retry
 */

const DEFAULT_MAX_RETRIES = 3;
const DEFAULT_BASE_DELAY = 1000; // 1 second

export const apiWithRetry = async (
  apiCall,
  options = {}
) => {
  const {
    maxRetries = DEFAULT_MAX_RETRIES,
    baseDelay = DEFAULT_BASE_DELAY,
    onRetry = () => {},
    shouldRetry = (error) => true,
  } = options;

  let lastError;
  
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      // If not first attempt, wait with exponential backoff
      if (attempt > 0) {
        const delay = baseDelay * Math.pow(2, attempt - 1);
        await new Promise(resolve => setTimeout(resolve, delay));
        onRetry(attempt, delay);
      }
      
      // Make the API call
      const result = await apiCall();
      return result;
      
    } catch (error) {
      lastError = error;
      
      // Check if we should retry
      if (!shouldRetry(error) || attempt === maxRetries) {
        throw error;
      }
      
    }
  }
  
  throw lastError;
};

/**
 * Check if error is retryable
 */
export const isRetryableError = (error) => {
  // Network errors are retryable
  if (error.name === 'NetworkError' || error.message?.includes('Failed to fetch')) {
    return true;
  }
  
  // Server errors (5xx) are retryable
  if (error.status >= 500 && error.status < 600) {
    return true;
  }
  
  // Rate limiting (429) is retryable
  if (error.status === 429) {
    return true;
  }
  
  // Timeout errors are retryable
  if (error.code === 'ETIMEDOUT' || error.message?.includes('timeout')) {
    return true;
  }
  
  // Client errors (4xx except 429) are not retryable
  if (error.status >= 400 && error.status < 500) {
    return false;
  }
  
  // Default to retryable for unknown errors
  return true;
};

/**
 * Create API functions with built-in retry logic
 */
export const createRetryableApi = (baseApiGet, baseApiPost) => {
  const retryableGet = (path, options = {}) => {
    return apiWithRetry(
      () => baseApiGet(path),
      {
        ...options,
        shouldRetry: isRetryableError,
      }
    );
  };
  
  const retryablePost = (path, body, options = {}) => {
    return apiWithRetry(
      () => baseApiPost(path, body),
      {
        ...options,
        shouldRetry: isRetryableError,
      }
    );
  };
  
  return { apiGet: retryableGet, apiPost: retryablePost };
};