// src/utils/retry.ts
import { Logger } from 'pino';

/** Basic sleep function */
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

/**
 * Performs an async operation with retry logic.
 * @param operation The async function to execute.
 * @param maxRetries Maximum number of retries.
 * @param delayMs Delay between retries in milliseconds.
 * @param logger Pino logger instance.
 * @param operationName Name of the operation for logging.
 * @returns The result of the operation.
 */
export async function performRetry<T>(
    operation: () => Promise<T>,
    maxRetries: number,
    delayMs: number,
    logger: Logger,
    operationName: string = 'Operation'
): Promise<T> {
    let attempts = 0;
    while (attempts <= maxRetries) {
        try {
            return await operation();
        } catch (error: any) {
            attempts++;
            logger.warn({ err: error, attempt: attempts, maxRetries, operationName },
                `${operationName} failed. Retrying in ${delayMs}ms... (Attempt <span class="math-inline">\{attempts\}/</span>{maxRetries})`
            );
            if (attempts > maxRetries) {
                logger.error({ err: error, operationName }, `${operationName} failed after ${maxRetries} retries.`);
                throw error; // Rethrow the error after exhausting retries
            }
            await delay(delayMs);
        }
    }
    // This line should theoretically be unreachable due to the throw in the catch block
    throw new Error(`${operationName} failed after exhausting retries.`);
}