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.
 */
export class BaseAbstractClient {
    eventSearchConfig;
    cachingMechanism;
    _isUpdated;
    firstHeightToSearch = 0;
    latestHeightSearched = 0;
    /**
     * 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.
     */
    constructor(eventSearchConfig = { from: 0, maxLookBack: 0 }, cachingMechanism) {
        this.eventSearchConfig = eventSearchConfig;
        this.cachingMechanism = cachingMechanism;
        this._isUpdated = false;
    }
    /**
     * Indicates whether the client has been updated since it was created.
     * @returns Whether the client has been updated since it was created.
     */
    get isUpdated() {
        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 isUpdated(value) {
        if (this._isUpdated === true && !value) {
            throw new Error("Cannot set isUpdated to false once it is true");
        }
        this._isUpdated = value;
    }
    /**
     * 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.
     */
    async updateSearchConfig(provider) {
        const from = this.firstHeightToSearch;
        let { to } = this.eventSearchConfig;
        if (isDefined(to)) {
            if (from > to) {
                throw new Error(`Invalid event search config from (${from}) > to (${to})`);
            }
        }
        else {
            to = await provider.getBlockNumber();
            if (to < from) {
                return UpdateFailureReason.AlreadyUpdated;
            }
        }
        const { maxLookBack } = this.eventSearchConfig;
        return { from, to, maxLookBack };
    }
    async updateSvmSearchConfig(provider, logger) {
        const from = this.firstHeightToSearch;
        let { to } = this.eventSearchConfig;
        if (isDefined(to)) {
            if (from > to) {
                throw new Error(`Invalid event search config from (${from}) > to (${to})`);
            }
        }
        else {
            const opts = undefined; // Inherit defaults
            const { slot } = await getNearestSlotTime(provider, opts, logger);
            to = Number(slot);
            if (to < from) {
                return UpdateFailureReason.AlreadyUpdated;
            }
        }
        const { maxLookBack } = this.eventSearchConfig;
        return { from, to, maxLookBack };
    }
    /**
     * Asserts that the client has been updated.
     */
    assertUpdated() {
        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.
     */
    hasCachingMechanism() {
        return isDefined(this.cachingMechanism);
    }
}
//# sourceMappingURL=BaseAbstractClient.js.map