import backoff from './backoff'
import { sleep } from './sleep'

export interface RetryOptions {
	delay?: number
	attempts?: number
	onRetry?(info: { attempt: number; delay: number; error: any }): void
	shouldRetry?(error: any): boolean
}

export default async function retry<T>(
	run: () => Promise<T>,
	{
		delay: backoffDelay = 1000,
		attempts = 15,
		onRetry,
		shouldRetry,
	}: RetryOptions = {},
) {
	for (let attempt = 1; attempt < attempts; attempt++) {
		try {
			return await run()
		} catch (error) {
			if (!shouldRetry || shouldRetry(error)) {
				const delay = backoff(attempt, backoffDelay)

				onRetry?.({ attempt, delay, error })

				await sleep(delay)
			} else {
				throw error
			}
		}
	}

	return run()
}
