import assert from 'node:assert';
import timers from 'timers/promises';
import util from 'node:util';

async function promiseRetry(options, asyncFunction) {
    assert.strictEqual(typeof options, 'object');
    assert(util.types.isAsyncFunction(asyncFunction));

    const { times, interval } = options;

    for (let i = 0; i < times; i++) {
        try {
            return await asyncFunction(i+1 /* attempt */);
        } catch (error) {
            if (options.log) options.log(`Attempt ${i+1} failed. Will retry: ${error.message} ${i === times-1 ? error.stack : ''}`); // only print stack on last error
            if (i === times - 1) throw error;
            if (options.retry && !options.retry(error)) throw error; // no more retry
            await timers.setTimeout(interval);
        }
    }
}

export default promiseRetry;
