import { __awaiter, __extends, __generator, __spreadArray } from "tslib";
import { SolanaClusterRpcFactory } from "./baseRpcFactories";
import { RateLimitedSolanaRpcFactory } from "./rateLimitedRpcFactory";
import { delay } from "../../utils";
import { getOriginFromURL } from "../../utils/NetworkUtils";
// This factory adds retry logic on top of the RateLimitedSolanaRpcFactory.
// It follows the same composition pattern as other factories in this module.
var RetrySolanaRpcFactory = /** @class */ (function (_super) {
    __extends(RetrySolanaRpcFactory, _super);
    function RetrySolanaRpcFactory(retries, retryDelaySeconds) {
        var _this = this;
        var rateLimitedConstructorParams = [];
        for (var _i = 2; _i < arguments.length; _i++) {
            rateLimitedConstructorParams[_i - 2] = arguments[_i];
        }
        // SolanaClusterRpcFactory shares the last two constructor parameters with RateLimitedSolanaRpcFactory.
        var superParams = rateLimitedConstructorParams.slice(-2);
        _this = _super.apply(this, superParams) || this;
        _this.retries = retries;
        _this.retryDelaySeconds = retryDelaySeconds;
        // Validate retry configuration
        if (_this.retries < 0 || !Number.isInteger(_this.retries)) {
            throw new Error("retries cannot be < 0 and must be an integer. Currently set to ".concat(_this.retries));
        }
        if (_this.retryDelaySeconds < 0) {
            throw new Error("retryDelaySeconds cannot be < 0. Currently set to ".concat(_this.retryDelaySeconds));
        }
        // Create the rate limited transport.
        var rateLimitedRpcFactory = new (RateLimitedSolanaRpcFactory.bind.apply(RateLimitedSolanaRpcFactory, __spreadArray([void 0], rateLimitedConstructorParams, false)))();
        _this.rateLimitedTransport = rateLimitedRpcFactory.createTransport();
        _this.logger = rateLimitedRpcFactory.logger;
        return _this;
    }
    RetrySolanaRpcFactory.prototype.createTransport = function () {
        var _this = this;
        return function () {
            var args = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                args[_i] = arguments[_i];
            }
            return _this._tryCall(function () { return _this.rateLimitedTransport.apply(_this, args); }, args);
        };
    };
    /**
     * Retry wrapper for transport calls with Solana-specific error handling.
     * @param transportCall Function that makes the transport call
     * @param args Original transport arguments for logging
     * @returns Promise that resolves to the transport response
     */
    RetrySolanaRpcFactory.prototype._tryCall = function (transportCall, args) {
        return __awaiter(this, void 0, void 0, function () {
            var method, retries, error_1;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        method = args[0].payload.method;
                        retries = this.retries;
                        _a.label = 1;
                    case 1:
                        if (!true) return [3 /*break*/, 7];
                        _a.label = 2;
                    case 2:
                        _a.trys.push([2, 4, , 6]);
                        return [4 /*yield*/, transportCall()];
                    case 3: return [2 /*return*/, _a.sent()];
                    case 4:
                        error_1 = _a.sent();
                        if (retries-- <= 0 || this.shouldFailImmediate(method, error_1)) {
                            throw error_1;
                        }
                        // Log retry attempt if logger is available
                        this.logger.debug({
                            at: "RetryRpcFactory",
                            message: "Retrying Solana RPC call",
                            provider: getOriginFromURL(this.clusterUrl),
                            method: method,
                            retryAttempt: this.retries - retries,
                            retryDelaySeconds: this.retryDelaySeconds,
                            error: error_1 === null || error_1 === void 0 ? void 0 : error_1.toString(),
                        });
                        return [4 /*yield*/, delay(this.retryDelaySeconds)];
                    case 5:
                        _a.sent();
                        return [3 /*break*/, 6];
                    case 6: return [3 /*break*/, 1];
                    case 7: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Determine whether a Solana RPC error indicates an unrecoverable error that should not be retried.
     * @param method RPC method name
     * @param error Error object from the RPC call
     * @returns True if the request should be aborted immediately, otherwise false
     */
    RetrySolanaRpcFactory.prototype.shouldFailImmediate = function (_method, _error) {
        // TODO: Decide which Solana RPC errors should be considered non-transitory and should not be retried.
        // For now, retry all errors.
        return false;
    };
    return RetrySolanaRpcFactory;
}(SolanaClusterRpcFactory));
export { RetrySolanaRpcFactory };
//# sourceMappingURL=retryRpcFactory.js.map