/**
 * Retry utilities for resilient operations
 * Implements exponential backoff, jitter, and circuit breaker patterns
 */

export interface RetryOptions {
  maxRetries?: number;
  initialDelay?: number;
  maxDelay?: number;
  factor?: number;
  jitter?: boolean;
  onRetry?: (error: Error, attempt: number) => void;
}

import { CircuitBreaker, type CircuitBreakerOptions, CircuitBreakerState } from './circuit-breaker';

export type { CircuitBreakerOptions };
export { CircuitBreakerState };

/**
 * Retry a function with exponential backoff
 */
export async function retry<T>(
  fn: () => Promise<T>,
  options: RetryOptions = {}
): Promise<T> {
  const {
    maxRetries = 3,
    initialDelay = 1000,
    maxDelay = 30000,
    factor = 2,
    jitter = true,
    onRetry,
  } = options;

  let lastError: Error | null = null;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error instanceof Error ? error : new Error(String(error));

      if (attempt === maxRetries) {
        break;
      }

      if (onRetry) {
        onRetry(lastError, attempt + 1);
      }

      const delay = Math.min(initialDelay * Math.pow(factor, attempt), maxDelay);
      const jitterValue = jitter ? Math.random() * 0.3 * delay : 0;
      const finalDelay = delay + jitterValue;

      await sleep(finalDelay);
    }
  }

  throw lastError || new Error('Retry failed');
}

/**
 * Sleep for a given number of milliseconds
 */
export function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

/**
 * Create a circuit breaker instance
 */
export function createCircuitBreaker(
  options?: CircuitBreakerOptions
): CircuitBreaker {
  return new CircuitBreaker(options);
}

export { CircuitBreaker };

