import { __assign, __awaiter, __generator, __spreadArray } from "tslib";
import { BorshEventCoder, utils } from "@coral-xyz/anchor";
import web3 from "@solana/kit";
/**
 * Reads all events for a specific program.
 */
export function readProgramEvents(rpc_1, program_1, anchorIdl_1) {
    return __awaiter(this, arguments, void 0, function (rpc, program, anchorIdl, finality, options) {
        var allSignatures, eventsWithSlots;
        var _this = this;
        if (finality === void 0) { finality = "confirmed"; }
        if (options === void 0) { options = { limit: 1000 }; }
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, searchSignaturesUntilLimit(rpc, program, options)];
                case 1:
                    allSignatures = _a.sent();
                    return [4 /*yield*/, Promise.all(allSignatures.map(function (signatureTransaction) { return __awaiter(_this, void 0, void 0, function () {
                            var events;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, readEvents(rpc, signatureTransaction.signature, program, anchorIdl, finality)];
                                    case 1:
                                        events = _a.sent();
                                        return [2 /*return*/, events.map(function (event) { return (__assign(__assign({}, event), { confirmationStatus: signatureTransaction.confirmationStatus || "Unknown", blockTime: signatureTransaction.blockTime || 0, signature: signatureTransaction.signature, slot: signatureTransaction.slot, name: event.name || "Unknown" })); })];
                                }
                            });
                        }); }))];
                case 2:
                    eventsWithSlots = _a.sent();
                    return [2 /*return*/, eventsWithSlots.flat()];
            }
        });
    });
}
function searchSignaturesUntilLimit(client_1, program_1) {
    return __awaiter(this, arguments, void 0, function (client, program, options) {
        var allSignatures, signatures;
        if (options === void 0) { options = { limit: 1000 }; }
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    allSignatures = [];
                    _a.label = 1;
                case 1: return [4 /*yield*/, client.rpc.getSignaturesForAddress(program, options).send()];
                case 2:
                    signatures = _a.sent();
                    allSignatures.push.apply(allSignatures, signatures);
                    // Update options for the next batch. Set before to the last fetched signature.
                    if (signatures.length > 0) {
                        options = __assign(__assign({}, options), { before: signatures[signatures.length - 1].signature });
                    }
                    if (options.limit && signatures.length < options.limit)
                        return [3 /*break*/, 4]; // Exit early if the number of signatures < limit
                    _a.label = 3;
                case 3: return [3 /*break*/, 1];
                case 4: return [2 /*return*/, allSignatures];
            }
        });
    });
}
/**
 * Reads events from a transaction.
 */
export function readEvents(client_1, txSignature_1, programId_1, programIdl_1) {
    return __awaiter(this, arguments, void 0, function (client, txSignature, programId, programIdl, commitment) {
        var txResult, txWithVersion;
        var _a;
        if (commitment === void 0) { commitment = "confirmed"; }
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, client.rpc
                        .getTransaction(txSignature, { encoding: "json", commitment: commitment, maxSupportedTransactionVersion: 0 })
                        .send()];
                case 1:
                    txResult = _b.sent();
                    if (txResult === null)
                        return [2 /*return*/, []];
                    txWithVersion = __assign(__assign({}, txResult), { version: (_a = txResult.version) !== null && _a !== void 0 ? _a : 0 });
                    return [2 /*return*/, processEventFromTx(txWithVersion, programId, programIdl)];
            }
        });
    });
}
/**
 * Processes events from a transaction.
 */
function processEventFromTx(txResult, programId, programIdl
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) {
    return __awaiter(this, void 0, void 0, function () {
        var eventAuthorities, events, pda, accountKeys, messageAccountKeys, _i, _a, ixBlock, _b, _c, ix, ixProgramId, singleIxAccount, ixData, eventData, event_1;
        var _d, _e, _f, _g, _h, _j, _k, _l;
        return __generator(this, function (_m) {
            switch (_m.label) {
                case 0:
                    if (!txResult)
                        return [2 /*return*/, []];
                    eventAuthorities = new Map();
                    events = [];
                    return [4 /*yield*/, web3.getProgramDerivedAddress({ programAddress: programId, seeds: ["__event_authority"] })];
                case 1:
                    pda = (_m.sent())[0];
                    eventAuthorities.set(programId, pda);
                    accountKeys = txResult.transaction.message.accountKeys;
                    messageAccountKeys = __spreadArray([], accountKeys, true);
                    // Order matters here. writable accounts must be processed before readonly accounts.
                    // See https://docs.anza.xyz/proposals/versioned-transactions#new-transaction-format
                    messageAccountKeys.push.apply(messageAccountKeys, ((_f = (_e = (_d = txResult === null || txResult === void 0 ? void 0 : txResult.meta) === null || _d === void 0 ? void 0 : _d.loadedAddresses) === null || _e === void 0 ? void 0 : _e.writable) !== null && _f !== void 0 ? _f : []));
                    messageAccountKeys.push.apply(messageAccountKeys, ((_j = (_h = (_g = txResult === null || txResult === void 0 ? void 0 : txResult.meta) === null || _g === void 0 ? void 0 : _g.loadedAddresses) === null || _h === void 0 ? void 0 : _h.readonly) !== null && _j !== void 0 ? _j : []));
                    for (_i = 0, _a = (_l = (_k = txResult.meta) === null || _k === void 0 ? void 0 : _k.innerInstructions) !== null && _l !== void 0 ? _l : []; _i < _a.length; _i++) {
                        ixBlock = _a[_i];
                        for (_b = 0, _c = ixBlock.instructions; _b < _c.length; _b++) {
                            ix = _c[_b];
                            ixProgramId = messageAccountKeys[ix.programIdIndex];
                            singleIxAccount = ix.accounts.length === 1 ? messageAccountKeys[ix.accounts[0]] : undefined;
                            if (ixProgramId !== undefined &&
                                singleIxAccount !== undefined &&
                                programId == ixProgramId &&
                                eventAuthorities.get(ixProgramId.toString()) == singleIxAccount) {
                                ixData = utils.bytes.bs58.decode(ix.data);
                                eventData = utils.bytes.base64.encode(Buffer.from(new Uint8Array(ixData).slice(8)));
                                event_1 = new BorshEventCoder(programIdl).decode(eventData);
                                events.push({
                                    program: programId,
                                    data: event_1 === null || event_1 === void 0 ? void 0 : event_1.data,
                                    name: event_1 === null || event_1 === void 0 ? void 0 : event_1.name,
                                });
                            }
                        }
                    }
                    return [2 /*return*/, events];
            }
        });
    });
}
/**
 * For a given fillStatusPDa & associated spokePool ProgramID, return the fill event.
 */
export function readFillEventFromFillStatusPda(client, fillStatusPda, programId, programIdl
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) {
    return __awaiter(this, void 0, void 0, function () {
        var signatures, events;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, searchSignaturesUntilLimit(client, fillStatusPda)];
                case 1:
                    signatures = _a.sent();
                    if (signatures.length === 0)
                        return [2 /*return*/, { event: null, slot: 0 }];
                    return [4 /*yield*/, readEvents(client, signatures[signatures.length - 1].signature, programId, programIdl)];
                case 2:
                    events = _a.sent();
                    return [2 /*return*/, { event: events[0], slot: Number(signatures[signatures.length - 1].slot) }];
            }
        });
    });
}
//# sourceMappingURL=solanaProgramUtils.js.map