/**
 * sinks/retry.ts
 *
 * Simple retry utility with exponential backoff for sink operations.
 * Used by the sink runner to retry transient failures (network timeouts,
 * HTTP 429/5xx) without requiring sinks to implement retry logic internally.
 *
 * Policy: 3 retries, exponential backoff (1s → 2s → 4s).
 *
 * @see docs/design-docs/report-store/sink-architecture.md
 */
const DEFAULT_MAX_RETRIES = 3;
const DEFAULT_BASE_DELAY_MS = 1000;
/**
 * Retry a sink publish operation with exponential backoff.
 *
 * Only retries on "failed" results — "success" and "skipped" are returned
 * immediately. Thrown exceptions are caught and converted to "failed" results.
 *
 * @param fn - The publish function to retry
 * @param maxRetries - Maximum number of retry attempts (default: 3)
 * @param baseDelayMs - Initial delay in milliseconds (default: 1000)
 * @returns The final SinkResult after all attempts
 */
export async function withRetry(fn, maxRetries = DEFAULT_MAX_RETRIES, baseDelayMs = DEFAULT_BASE_DELAY_MS) {
    let lastResult = { error: "No attempts made", status: "failed" };
    for (let attempt = 0; attempt <= maxRetries; attempt++) {
        try {
            const result = await fn();
            // Success and skipped are terminal — no retry
            if (result.status !== "failed") {
                return result;
            }
            lastResult = result;
        }
        catch (error) {
            lastResult = {
                error: error instanceof Error ? error.message : String(error),
                status: "failed",
            };
        }
        // Don't delay after the last attempt
        if (attempt < maxRetries) {
            const delayMs = baseDelayMs * Math.pow(2, attempt);
            await sleep(delayMs);
        }
    }
    return lastResult;
}
function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}
