import { __awaiter, __generator } from "tslib";
import { providers } from "ethers";
import { isDefined } from "../utils";
import { getNearestSlotTime } from "../arch/svm";
export var UpdateFailureReason;
(function (UpdateFailureReason) {
    UpdateFailureReason[UpdateFailureReason["NotReady"] = 0] = "NotReady";
    UpdateFailureReason[UpdateFailureReason["AlreadyUpdated"] = 1] = "AlreadyUpdated";
    UpdateFailureReason[UpdateFailureReason["BadRequest"] = 2] = "BadRequest";
    UpdateFailureReason[UpdateFailureReason["RPCError"] = 3] = "RPCError";
})(UpdateFailureReason || (UpdateFailureReason = {}));
export function isUpdateFailureReason(x) {
    return Number.isInteger(x);
}
/**
 * Base class for all clients to extend.
 */
var BaseAbstractClient = /** @class */ (function () {
    /**
     * Creates a new client.
     * @param cachingMechanism The caching mechanism to use for this client. If not provided, the client will not rely on an external cache.
     */
    function BaseAbstractClient(eventSearchConfig, cachingMechanism) {
        if (eventSearchConfig === void 0) { eventSearchConfig = { from: 0, maxLookBack: 0 }; }
        this.eventSearchConfig = eventSearchConfig;
        this.cachingMechanism = cachingMechanism;
        this.firstHeightToSearch = 0;
        this.latestHeightSearched = 0;
        this._isUpdated = false;
    }
    Object.defineProperty(BaseAbstractClient.prototype, "isUpdated", {
        /**
         * Indicates whether the client has been updated since it was created.
         * @returns Whether the client has been updated since it was created.
         */
        get: function () {
            return this._isUpdated;
        },
        /**
         * Sets whether the client has been updated since it was created.
         * @param value Whether the client has been updated since it was created.
         * @throws Error if the client has already been updated and the value is false.
         */
        set: function (value) {
            if (this._isUpdated === true && !value) {
                throw new Error("Cannot set isUpdated to false once it is true");
            }
            this._isUpdated = value;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Validates and updates the stored EventSearchConfig in advance of an update() call.
     * Use isEventSearchConfig() to discriminate the result.
     * @provider Ethers RPC provider instance.
     * @returns An EventSearchConfig instance if valid, otherwise an UpdateFailureReason.
     */
    BaseAbstractClient.prototype.updateSearchConfig = function (provider) {
        return __awaiter(this, void 0, void 0, function () {
            var from, to, slot, maxLookBack;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        from = this.firstHeightToSearch;
                        to = this.eventSearchConfig.to;
                        if (!isDefined(to)) return [3 /*break*/, 1];
                        if (from > to) {
                            throw new Error("Invalid event search config from (".concat(from, ") > to (").concat(to, ")"));
                        }
                        return [3 /*break*/, 6];
                    case 1:
                        if (!(provider instanceof providers.Provider)) return [3 /*break*/, 3];
                        return [4 /*yield*/, provider.getBlockNumber()];
                    case 2:
                        to = _a.sent();
                        return [3 /*break*/, 5];
                    case 3: return [4 /*yield*/, getNearestSlotTime(provider)];
                    case 4:
                        slot = (_a.sent()).slot;
                        to = Number(slot);
                        _a.label = 5;
                    case 5:
                        if (to < from) {
                            return [2 /*return*/, UpdateFailureReason.AlreadyUpdated];
                        }
                        _a.label = 6;
                    case 6:
                        maxLookBack = this.eventSearchConfig.maxLookBack;
                        return [2 /*return*/, { from: from, to: to, maxLookBack: maxLookBack }];
                }
            });
        });
    };
    /**
     * Asserts that the client has been updated.
     */
    BaseAbstractClient.prototype.assertUpdated = function () {
        if (!this.isUpdated) {
            throw new Error("Client not updated");
        }
    };
    /**
     * Determines if the client has an external cache.
     * @returns Whether the client has an external cache.
     */
    BaseAbstractClient.prototype.hasCachingMechanism = function () {
        return isDefined(this.cachingMechanism);
    };
    return BaseAbstractClient;
}());
export { BaseAbstractClient };
//# sourceMappingURL=BaseAbstractClient.js.map