import { exponentialBackoff } from "./backoff";
import { sleep } from "../utils/sleep";

export interface RetryOptions {
  /** Número máximo de reintentos (default = 3). */
  retries?: number;
  /** Retardo base en ms (default = 100). */
  baseDelay?: number;
  /** Retardo máximo en ms (default = 1000). */
  maxDelay?: number;
}

/**
 * Reintenta una función asíncrona en caso de fallo, usando backoff exponencial.
 * @param fn Función que retorna una promesa.
 * @param options Configuración de reintentos.
 * @returns Resultado de la función si tiene éxito.
 * @throws Último error si agota los intentos.
 */
export async function retry<T>(
  fn: () => Promise<T>,
  options: RetryOptions = {}
): Promise<T> {
  const { retries = 3, baseDelay = 100, maxDelay = 1000 } = options;

  let lastError: unknown;

  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      lastError = err;
      if (attempt < retries) {
        const delay = exponentialBackoff(attempt, baseDelay, maxDelay);
        await sleep(delay);
      }
    }
  }

  throw lastError;
}
