"use strict";

/**
 * Async utilities for common asynchronous patterns and error handling
 */

/**
 * Wrapper for async operations with automatic error handling
 */
export async function withErrorHandling(operation, errorHandler, context) {
  try {
    return await operation();
  } catch (error) {
    if (errorHandler) {
      errorHandler(error);
    } else {
      console.error(`Error in ${context || 'operation'}:`, error);
    }
    return null;
  }
}

/**
 * Execute multiple async operations in parallel with error handling
 */
export async function parallelWithErrorHandling(operations, errorHandler) {
  const results = await Promise.allSettled(operations.map((op, index) => withErrorHandling(op, error => errorHandler?.(error, index))));
  return results.map(result => result.status === 'fulfilled' ? result.value : null);
}

/**
 * Retry an async operation with exponential backoff
 */
export async function retryAsync(operation, maxRetries = 3, baseDelay = 1000, shouldRetry) {
  let lastError;
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error;
      if (attempt === maxRetries) {
        break;
      }
      if (shouldRetry && !shouldRetry(error)) {
        break;
      }
      const delay = baseDelay * Math.pow(2, attempt);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
  throw lastError;
}

/**
 * Debounce async function calls
 */
export function debounceAsync(func, delay) {
  let timeoutId;
  const lastPromise = null;
  return (...args) => {
    return new Promise((resolve, reject) => {
      clearTimeout(timeoutId);
      timeoutId = setTimeout(async () => {
        try {
          const result = await func(...args);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      }, delay);
    });
  };
}

/**
 * Throttle async function calls
 */
export function throttleAsync(func, limit, interval) {
  let inThrottle = false;
  let lastPromise = null;
  return (...args) => {
    if (inThrottle) {
      return lastPromise;
    }
    inThrottle = true;
    lastPromise = func(...args);
    setTimeout(() => {
      inThrottle = false;
    }, interval);
    return lastPromise;
  };
}

/**
 * Execute async operations sequentially with progress tracking
 */
export async function sequentialWithProgress(operations, onProgress) {
  const results = [];
  for (let i = 0; i < operations.length; i++) {
    const result = await operations[i]();
    results.push(result);
    onProgress?.(i + 1, operations.length);
  }
  return results;
}

/**
 * Batch async operations
 */
export async function batchAsync(items, batchSize, processor) {
  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize);
    await processor(batch);
  }
}

/**
 * Create a cancellable async operation
 */
export function createCancellableAsync(operation) {
  let abortController = null;
  return {
    execute: async () => {
      abortController = new AbortController();
      return await operation(abortController.signal);
    },
    cancel: () => {
      abortController?.abort();
    }
  };
}

/**
 * Timeout wrapper for async operations
 */
export async function withTimeout(operation, timeoutMs, timeoutMessage) {
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => {
      reject(new Error(timeoutMessage || `Operation timed out after ${timeoutMs}ms`));
    }, timeoutMs);
  });
  return Promise.race([operation, timeoutPromise]);
}

/**
 * Cache async operation results
 */
export function createAsyncCache(ttl = 5 * 60 * 1000 // 5 minutes default
) {
  const cache = new Map();
  return {
    get: key => {
      const item = cache.get(key);
      if (!item) return null;
      if (Date.now() - item.timestamp > ttl) {
        cache.delete(key);
        return null;
      }
      return item.data;
    },
    set: (key, data) => {
      cache.set(key, {
        data,
        timestamp: Date.now()
      });
    },
    clear: () => {
      cache.clear();
    },
    delete: key => {
      return cache.delete(key);
    }
  };
}

/**
 * Execute async operation with loading state
 */
export async function withLoadingState(operation, setLoading) {
  setLoading(true);
  try {
    return await operation();
  } finally {
    setLoading(false);
  }
}

/**
 * Create a promise that resolves after a delay
 */
export const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

/**
 * Execute async operation with retry on specific errors
 */
export async function retryOnError(operation, retryableErrors, maxRetries = 3) {
  return retryAsync(operation, maxRetries, 1000, error => {
    const errorCode = error?.code || error?.status || error?.message;
    return retryableErrors.includes(errorCode);
  });
}
//# sourceMappingURL=asyncUtils.js.map