"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SVMSpokePoolClient = void 0;
var tslib_1 = require("tslib");
var svm_1 = require("../../arch/svm");
var utils_1 = require("../../utils");
var BaseAbstractClient_1 = require("../BaseAbstractClient");
var SpokePoolClient_1 = require("./SpokePoolClient");
var types_1 = require("./types");
var SVMSpokePoolClient = (function (_super) {
    tslib_1.__extends(SVMSpokePoolClient, _super);
    function SVMSpokePoolClient(logger, hubPoolClient, chainId, deploymentSlot, eventSearchConfig, svmEventsClient, programId, statePda) {
        var _this = _super.call(this, logger, hubPoolClient, chainId, Number(deploymentSlot), eventSearchConfig) || this;
        _this.svmEventsClient = svmEventsClient;
        _this.programId = programId;
        _this.statePda = statePda;
        _this.type = types_1.SVM_SPOKE_POOL_CLIENT_TYPE;
        _this.spokePoolAddress = utils_1.SvmAddress.from(programId.toString());
        return _this;
    }
    SVMSpokePoolClient.create = function (logger, hubPoolClient, chainId, deploymentSlot, eventSearchConfig, rpc) {
        if (eventSearchConfig === void 0) { eventSearchConfig = { from: 0, maxLookBack: 0 }; }
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var svmEventsClient, programId, statePda;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4, svm_1.SvmCpiEventsClient.create(rpc)];
                    case 1:
                        svmEventsClient = _a.sent();
                        programId = svmEventsClient.getProgramAddress();
                        return [4, (0, svm_1.getStatePda)(programId)];
                    case 2:
                        statePda = _a.sent();
                        return [2, new SVMSpokePoolClient(logger, hubPoolClient, chainId, deploymentSlot, eventSearchConfig, svmEventsClient, programId, statePda)];
                }
            });
        });
    };
    SVMSpokePoolClient.createWithExistingEventClient = function (logger, hubPoolClient, chainId, deploymentSlot, eventSearchConfig, eventClient) {
        if (eventSearchConfig === void 0) { eventSearchConfig = { from: 0, maxLookBack: 0 }; }
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var programId, statePda;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        programId = eventClient.getProgramAddress();
                        return [4, (0, svm_1.getStatePda)(programId)];
                    case 1:
                        statePda = _a.sent();
                        return [2, new SVMSpokePoolClient(logger, hubPoolClient, chainId, deploymentSlot, eventSearchConfig, eventClient, programId, statePda)];
                }
            });
        });
    };
    SVMSpokePoolClient.prototype._queryableEventNames = function () {
        var internalEventNames = Object.values(svm_1.SVMEventNames);
        return internalEventNames.filter(function (e) { return SpokePoolClient_1.knownEventNames.includes(e); });
    };
    SVMSpokePoolClient.prototype._update = function (eventsToQuery) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var searchConfig, reason, eventSearchConfigs, spokePoolAddress, timerStart, _a, currentTime, eventsQueried, errMsg;
            var _this = this;
            return tslib_1.__generator(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4, this.updateSearchConfig(this.svmEventsClient.getRpc())];
                    case 1:
                        searchConfig = _b.sent();
                        if ((0, BaseAbstractClient_1.isUpdateFailureReason)(searchConfig)) {
                            reason = searchConfig;
                            return [2, { success: false, reason: reason }];
                        }
                        eventSearchConfigs = eventsToQuery.map(function (eventName) {
                            if (!_this._queryableEventNames().includes(eventName)) {
                                throw new Error("SpokePoolClient: Cannot query unrecognised SpokePool event name: ".concat(eventName));
                            }
                            var _searchConfig = tslib_1.__assign({}, searchConfig);
                            return _searchConfig;
                        });
                        spokePoolAddress = this.svmEventsClient.getProgramAddress();
                        this.log("debug", "Updating SpokePool client for chain ".concat(this.chainId), {
                            eventsToQuery: eventsToQuery,
                            searchConfig: searchConfig,
                            spokePool: spokePoolAddress,
                        });
                        timerStart = Date.now();
                        return [4, Promise.all(tslib_1.__spreadArray([
                                this.getTimeAt(searchConfig.to)
                            ], eventsToQuery.map(function (eventName, idx) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
                                var config, events;
                                return tslib_1.__generator(this, function (_a) {
                                    switch (_a.label) {
                                        case 0:
                                            config = eventSearchConfigs[idx];
                                            return [4, this.svmEventsClient.queryEvents(eventName, BigInt(config.from), BigInt(config.to), {
                                                    limit: config.maxLookBack,
                                                })];
                                        case 1:
                                            events = _a.sent();
                                            return [2, events.map(function (event) { return (tslib_1.__assign({ txnRef: event.signature, blockNumber: Number(event.slot), txnIndex: 0, logIndex: 0 }, (0, svm_1.unwrapEventData)(event.data))); })];
                                    }
                                });
                            }); }), true))];
                    case 2:
                        _a = _b.sent(), currentTime = _a[0], eventsQueried = _a.slice(1);
                        this.log("debug", "Time to query new events from RPC for ".concat(this.chainId, ": ").concat(Date.now() - timerStart, " ms"));
                        if (currentTime < this.currentTime) {
                            errMsg = "currentTime: ".concat(currentTime, " < ").concat(this.currentTime);
                            throw new Error("SvmSpokePoolClient::update: ".concat(errMsg));
                        }
                        eventsQueried.forEach(function (events) { return (0, utils_1.sortEventsAscendingInPlace)(events); });
                        return [2, {
                                success: true,
                                currentTime: Number(currentTime),
                                searchEndBlock: searchConfig.to,
                                events: eventsQueried,
                            }];
                }
            });
        });
    };
    SVMSpokePoolClient.prototype.getMaxFillDeadlineInRange = function (_startSlot, _endSlot) {
        return (0, svm_1.getFillDeadline)(this.svmEventsClient.getRpc(), this.statePda);
    };
    SVMSpokePoolClient.prototype.getTimestampForBlock = function (slot) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var _slot, timestamp;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _slot = BigInt(slot);
                        _a.label = 1;
                    case 1: return [4, (0, svm_1.getTimestampForSlot)(this.svmEventsClient.getRpc(), _slot)];
                    case 2:
                        timestamp = _a.sent();
                        if ((0, utils_1.isDefined)(timestamp)) {
                            return [2, timestamp];
                        }
                        _a.label = 3;
                    case 3:
                        if (--_slot > 0) return [3, 1];
                        _a.label = 4;
                    case 4: throw new Error("Unable to resolve time at or before ".concat((0, utils_1.getNetworkName)(this.chainId), " slot ").concat(slot));
                }
            });
        });
    };
    SVMSpokePoolClient.prototype.getTimeAt = function (slot) {
        return this.getTimestampForBlock(slot);
    };
    SVMSpokePoolClient.prototype.findDeposit = function (depositId) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var deposit, _a;
            var _b, _c;
            return tslib_1.__generator(this, function (_d) {
                switch (_d.label) {
                    case 0: return [4, (0, svm_1.findDeposit)(this.svmEventsClient, depositId)];
                    case 1:
                        deposit = _d.sent();
                        if (!deposit) {
                            return [2, {
                                    found: false,
                                    code: utils_1.InvalidFill.DepositIdNotFound,
                                    reason: "Deposit with ID ".concat(depositId, " not found"),
                                }];
                        }
                        _b = {
                            found: true
                        };
                        _a = [tslib_1.__assign({}, deposit)];
                        _c = {};
                        return [4, this.getBlockNumber(Number(deposit.quoteTimestamp))];
                    case 2: return [2, (_b.deposit = tslib_1.__assign.apply(void 0, _a.concat([(_c.quoteBlockNumber = _d.sent(), _c.originChainId = this.chainId, _c.fromLiteChain = this.isOriginLiteChain(deposit), _c.toLiteChain = this.isDestinationLiteChain(deposit), _c)])),
                            _b)];
                }
            });
        });
    };
    SVMSpokePoolClient.prototype.relayFillStatus = function (relayData, atHeight) {
        return (0, svm_1.relayFillStatus)(this.programId, relayData, this.chainId, this.svmEventsClient, atHeight);
    };
    SVMSpokePoolClient.prototype.fillStatusArray = function (relayData, atHeight, destinationChainId) {
        destinationChainId !== null && destinationChainId !== void 0 ? destinationChainId : (destinationChainId = this.chainId);
        return (0, svm_1.fillStatusArray)(this.programId, relayData, destinationChainId, this.svmEventsClient, atHeight, this.logger);
    };
    return SVMSpokePoolClient;
}(SpokePoolClient_1.SpokePoolClient));
exports.SVMSpokePoolClient = SVMSpokePoolClient;
//# sourceMappingURL=SVMSpokePoolClient.js.map