/**
 * Resilience utilities combining retry, circuit breaker, and timeout
 */

import { retry, type RetryOptions } from './retry';
import { CircuitBreaker, type CircuitBreakerOptions } from './circuit-breaker';
import { withTimeout } from './timeout';

export interface ResilientOptions extends RetryOptions {
  timeout?: number;
  circuitBreaker?: CircuitBreakerOptions;
  circuitBreakerInstance?: CircuitBreaker;
}

/**
 * Execute a function with retry, circuit breaker, and timeout protection
 */
export async function resilient<T>(
  fn: () => Promise<T>,
  options: ResilientOptions = {}
): Promise<T> {
  const { timeout, circuitBreaker, circuitBreakerInstance, ...retryOptions } = options;

  // Create circuit breaker if not provided
  let breaker = circuitBreakerInstance;
  if (!breaker && circuitBreaker) {
    breaker = new CircuitBreaker(circuitBreaker);
  }

  // Wrap function with circuit breaker
  const executeFn = breaker
    ? () => breaker!.execute(fn)
    : fn;

  // Wrap with timeout if specified
  const executeWithTimeout = timeout
    ? () => withTimeout(executeFn(), timeout, 'Operation timed out')
    : executeFn;

  // Execute with retry
  return retry(executeWithTimeout, retryOptions);
}

/**
 * Create a resilient function wrapper
 */
export function createResilientFunction<T extends (...args: unknown[]) => Promise<unknown>>(
  fn: T,
  options: ResilientOptions = {}
): T {
  return ((...args: Parameters<T>) => {
    return resilient(() => fn(...args), options);
  }) as T;
}

