"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Retryable = exports.AsyncRetryable = void 0;
var DEFAULT_DELAY = 100;
var Info = /** @class */ (function () {
    function Info(num) {
        this.count = num;
    }
    return Info;
}());
var AsyncRetryable = /** @class */ (function () {
    function AsyncRetryable(polly) {
        this.config = polly;
    }
    AsyncRetryable.prototype.forever = function () {
        this.config.isForever = true;
        return this;
    };
    AsyncRetryable.prototype.executeForPromise = function (fn) {
        var _this = this;
        var count = 0;
        return new Promise(function (resolve, reject) {
            var attempt = function () {
                fn(new Info(count))
                    .then(function (r) {
                    resolve(r);
                })
                    .catch(function (e) {
                    if (!_this.config.handleFn(e)) {
                        reject(e);
                        return;
                    }
                    if (count < _this.config.numRetries) {
                        count++;
                    }
                    else if (_this.config.isForever) {
                        count = 0;
                    }
                    else {
                        reject(e);
                        return;
                    }
                    setTimeout(attempt, _this.config.delays ? _this.config.delays[count] : DEFAULT_DELAY);
                });
            };
            setTimeout(attempt, 5);
        })
            .then(function (a) {
            return a;
        })
            .catch(function (e) {
            return e;
        });
    };
    return AsyncRetryable;
}());
exports.AsyncRetryable = AsyncRetryable;
var Retryable = /** @class */ (function (_super) {
    __extends(Retryable, _super);
    function Retryable(polly) {
        return _super.call(this, polly) || this;
    }
    Retryable.prototype.execute = function (fn) {
        var count = 0;
        var maxIterations = this.config.isForever ? 10000 : this.config.numRetries + 1; // Safety limit for forever loops
        while (count < maxIterations) {
            try {
                return fn(new Info(count));
            }
            catch (ex) {
                if (!this.config.handleFn(ex)) {
                    throw ex;
                }
                if (count < this.config.numRetries) {
                    count++;
                }
                else if (this.config.isForever) {
                    count = 0;
                }
                else {
                    throw ex;
                }
            }
        }
        // If we somehow reach here, throw an error
        throw new Error('Maximum retry iterations exceeded');
    };
    return Retryable;
}(AsyncRetryable));
exports.Retryable = Retryable;
var Polly = /** @class */ (function () {
    function Polly() {
    }
    Polly.prototype.handle = function (fn) {
        this.handleFn = fn;
        return this;
    };
    Polly.prototype.retry = function (numRetries) {
        this.numRetries = numRetries;
        return new Retryable(this);
    };
    Polly.prototype.forever = function () {
        this.isForever = true;
        return this;
    };
    Polly.prototype.waitAndRetry = function (delays) {
        if (typeof delays === 'number') {
            this.numRetries = delays;
            this.delays = Polly.getDelays(delays);
        }
        else {
            this.delays = delays;
            this.numRetries = delays.length;
        }
        return new AsyncRetryable(this);
    };
    Polly.getDelays = function (count) {
        var delays = [];
        var delay = 100;
        for (var i = 0; i < count; i++) {
            delays.push(delay);
            delay = 2 * delay;
        }
        return delays;
    };
    return Polly;
}());
exports.default = Polly;
//# sourceMappingURL=Polly.js.map