import { SolanaContext } from './solana-context.js';
import { ListStateStorage } from '@sentio/runtime';
import { ALL_ADDRESS } from '../core/index.js';
import { SolanaChainId } from '@sentio/chain';
import { getHandlerName, proxyProcessor } from '../utils/metrics.js';
export class SolanaProcessorState extends ListStateStorage {
    static INSTANCE = new SolanaProcessorState();
}
export class SolanaBaseProcessor {
    instructionHandlerMap = new Map();
    blockHandlers = [];
    address;
    endpoint;
    contractName;
    baseLabels;
    network;
    processInnerInstruction;
    config = { startSlot: 0n };
    instructionCoder;
    decodeInstruction(rawInstruction) {
        if (this.instructionCoder) {
            return this.instructionCoder.decode(rawInstruction, 'base58');
        }
        return null;
    }
    fromParsedInstruction;
    constructor(options) {
        this.address = options.address;
        this.contractName = options.name || '';
        this.processInnerInstruction = options.processInnerInstruction || false;
        this.network = options.network || SolanaChainId.SOLANA_MAINNET;
        if (options.instructionCoder) {
            this.instructionCoder = options.instructionCoder;
        }
        if (options.startBlock) {
            this.startSlot(options.startBlock);
        }
        if (options.endBlock) {
            this.endBlock(options.endBlock);
        }
        this.endpoint = options.network || 'https://api.mainnet-beta.solana.com';
        this.baseLabels = options.baseLabels;
        SolanaProcessorState.INSTANCE.addValue(this);
    }
    onInstruction(instructionName, handler, handlerOptions) {
        this.instructionHandlerMap.set(instructionName, { handler, handlerOptions });
        return this;
    }
    onTimeInterval(handler, timeIntervalInMinutes = 60, backfillTimeIntervalInMinutes = 240) {
        return this.onInterval(handler, { recentInterval: timeIntervalInMinutes, backfillInterval: backfillTimeIntervalInMinutes }, undefined);
    }
    onBlockInterval(handler, blockInterval = 1000, backfillBlockInterval = 4000) {
        return this.onInterval(handler, undefined, {
            recentInterval: blockInterval,
            backfillInterval: backfillBlockInterval
        });
    }
    onInterval(handler, timeInterval, slotInterval) {
        this.blockHandlers.push({
            handler: handler,
            timeIntervalInMinutes: timeInterval,
            slotInterval: slotInterval,
            handlerName: getHandlerName()
        });
        return this;
    }
    getParsedInstruction(ins) {
        if (ins) {
            if (ins.info) {
                return this.fromParsedInstruction ? this.fromParsedInstruction(ins) : null;
            }
            if (this.decodeInstruction != null) {
                return this.decodeInstruction(ins);
            }
        }
        return null;
    }
    getInstructionHandler(parsedInstruction) {
        return this.instructionHandlerMap.get(parsedInstruction.name);
    }
    async handleInstruction(parsedInstruction, accounts, handlerEntry, data) {
        let transaction = undefined;
        if (data.rawTransaction) {
            transaction = JSON.parse(data.rawTransaction);
        }
        const ctx = new SolanaContext(this.contractName, this.network, this.address, data.slot, this.baseLabels, transaction);
        await handlerEntry.handler(parsedInstruction, ctx, accounts);
        return ctx.stopAndGetResult();
    }
    async handleBlock(rawBlock, handlerEntry) {
        const ctx = new SolanaContext(this.contractName, this.network, this.address, rawBlock.slot, this.baseLabels);
        const block = JSON.parse(rawBlock.rawBlock);
        await handlerEntry.handler(block, ctx);
        return ctx.stopAndGetResult();
    }
    async getPartitionKey(parsedInstruction, handlerEntry) {
        const p = handlerEntry.handlerOptions?.partitionKey;
        if (!p)
            return undefined;
        if (typeof p === 'function') {
            return p(parsedInstruction);
        }
        return p;
    }
    startSlot(startSlot) {
        this.config.startSlot = BigInt(startSlot);
        return this;
    }
    endBlock(endBlock) {
        this.config.endSlot = BigInt(endBlock);
        return this;
    }
}
export class SolanaGlobalProcessor extends SolanaBaseProcessor {
    static bind(options) {
        return new SolanaGlobalProcessor({ ...options, address: ALL_ADDRESS });
    }
    constructor(options) {
        super(options);
        return proxyProcessor(this);
    }
}
//# sourceMappingURL=solana-processor.js.map