import { MoveFetchConfig, MoveOwnerType } from '@sentio/protos';
import { ListStateStorage } from '@sentio/runtime';
import { SuiNetwork } from './network.js';
import { SuiContext, SuiObjectChangeContext, SuiObjectContext } from './context.js';
import { ALL_ADDRESS } from '../core/index.js';
import { configure, DEFAULT_FETCH_CONFIG } from './sui-processor.js';
import { accountTypeString } from '../move/index.js';
import { ServerError, Status } from 'nice-grpc';
import { getHandlerName, proxyProcessor } from '../utils/metrics.js';
export const DEFAULT_ACCOUNT_FETCH_CONFIG = {
    owned: false
};
export class SuiAccountProcessorState extends ListStateStorage {
    static INSTANCE = new SuiAccountProcessorState();
}
export class SuiBaseObjectOrAddressProcessor {
    config;
    ownerType;
    templateId;
    objectHandlers = [];
    objectChangeHandlers = [];
    // static bind(options: SuiObjectsBindOptions): SuiBaseObjectsProcessor<any> {
    //   return new SuiBaseObjectsProcessor(options)
    // }
    constructor(options) {
        if (options.ownerType === MoveOwnerType.TYPE) {
            this.config = {
                startCheckpoint: options.startCheckpoint || 0n,
                endCheckpoint: options.endCheckpoint,
                address: options.address === '*' ? '*' : accountTypeString(options.address),
                network: options.network || SuiNetwork.MAIN_NET,
                baseLabels: options.baseLabels
            };
        }
        else {
            this.config = configure(options);
        }
        this.ownerType = options.ownerType;
        SuiAccountProcessorState.INSTANCE.addValue(this);
        return proxyProcessor(this);
    }
    getChainId() {
        return this.config.network;
    }
    onInterval(handler, //(resources: SuiMoveObject[], ctx: SuiObjectsContext) => PromiseOrVoid,
    timeInterval, checkpointInterval, type, fetchConfig, handlerName = getHandlerName()) {
        const processor = this;
        this.objectHandlers.push({
            handlerName,
            handler: async function (data) {
                const ctx = new SuiObjectContext(processor.config.network, data.objectId, data.objectVersion, data.slot, data.timestamp || new Date(0), processor.config.baseLabels);
                await processor.doHandle(handler, data, ctx);
                return ctx.stopAndGetResult();
            },
            timeIntervalInMinutes: timeInterval,
            checkPointInterval: checkpointInterval,
            type,
            fetchConfig: { ...DEFAULT_ACCOUNT_FETCH_CONFIG, ...fetchConfig }
        });
        return this;
    }
}
class SuiBaseObjectOrAddressProcessorInternal extends SuiBaseObjectOrAddressProcessor {
    onTimeInterval(handler, timeIntervalInMinutes = 60, backfillTimeIntervalInMinutes = 240, type, fetchConfig) {
        return this.onInterval(handler, {
            recentInterval: timeIntervalInMinutes,
            backfillInterval: backfillTimeIntervalInMinutes
        }, undefined, type, fetchConfig);
    }
    onCheckpointInterval(handler, checkpointInterval = 100000, backfillCheckpointInterval = 400000, type, fetchConfig) {
        return this.onInterval(handler, undefined, { recentInterval: checkpointInterval, backfillInterval: backfillCheckpointInterval }, type, fetchConfig);
    }
}
export class SuiAddressProcessor extends SuiBaseObjectOrAddressProcessorInternal {
    callHandlers = [];
    static bind(options) {
        return new SuiAddressProcessor({ ...options, ownerType: MoveOwnerType.ADDRESS });
    }
    async doHandle(handler, data, ctx) {
        return handler(data.rawObjects.map((o) => JSON.parse(o)), ctx);
    }
    onTransactionBlock(handler, filter, fetchConfig) {
        const _fetchConfig = MoveFetchConfig.fromPartial({ ...DEFAULT_FETCH_CONFIG, ...fetchConfig });
        const _filter = {
            fromAndToAddress: {
                from: '',
                to: this.config.address
            },
            ...filter
        };
        const processor = this;
        this.callHandlers.push({
            handlerName: getHandlerName(),
            handler: async function (data) {
                if (!data.rawTransaction) {
                    throw new ServerError(Status.INVALID_ARGUMENT, 'transaction is null');
                }
                const tx = JSON.parse(data.rawTransaction);
                const ctx = new SuiContext('object', processor.config.network, processor.config.address, data.timestamp || new Date(0), data.slot, tx, 0, processor.config.baseLabels);
                if (tx) {
                    await handler(tx, ctx);
                }
                return ctx.stopAndGetResult();
            },
            filters: [{ ..._filter, function: '' }],
            fetchConfig: _fetchConfig
        });
        return this;
    }
}
export class SuiObjectProcessor extends SuiBaseObjectOrAddressProcessorInternal {
    static bind(options) {
        return new SuiObjectProcessor({
            address: options.objectId,
            network: options.network,
            startCheckpoint: options.startCheckpoint,
            endCheckpoint: options.endCheckpoint,
            ownerType: MoveOwnerType.OBJECT,
            baseLabels: options.baseLabels
        });
    }
    async doHandle(handler, data, ctx) {
        if (!data.rawSelf) {
            console.log(`Sui object not existed in ${ctx.checkpoint}, please specific a start time`);
            return;
        }
        return handler(JSON.parse(data.rawSelf), data.rawObjects.map((o) => JSON.parse(o)), ctx);
    }
}
export class SuiObjectTypeProcessor extends SuiBaseObjectOrAddressProcessor {
    objectType;
    static bind(options) {
        const processor = new SuiObjectTypeProcessor({
            address: ALL_ADDRESS, // current only support on all address
            network: options.network,
            startCheckpoint: options.startCheckpoint,
            endCheckpoint: options.endCheckpoint,
            ownerType: MoveOwnerType.TYPE,
            baseLabels: options.baseLabels
        });
        processor.objectType = options.objectType;
        return processor;
    }
    async doHandle(handler, data, ctx) {
        if (!data.rawSelf) {
            console.log(`Sui object not existed in ${ctx.checkpoint}, please specific a start time`);
            return;
        }
        const object = await ctx.coder.filterAndDecodeObjects(this.objectType, [JSON.parse(data.rawSelf)]);
        return handler(object[0], data.rawObjects.map((o) => JSON.parse(o)), ctx);
    }
    onObjectChange(handler) {
        if (this.config.network === SuiNetwork.TEST_NET) {
            throw new ServerError(Status.INVALID_ARGUMENT, 'object change not supported in testnet');
        }
        const processor = this;
        this.objectChangeHandlers.push({
            handlerName: getHandlerName(),
            handler: async function (data) {
                const ctx = new SuiObjectChangeContext(processor.config.network, processor.config.address, data.timestamp || new Date(0), data.slot, data.txDigest, processor.config.baseLabels);
                await handler(data.rawChanges.map((r) => JSON.parse(r)), ctx);
                return ctx.stopAndGetResult();
            },
            type: [this.objectType.getSignature()]
        });
        return this;
    }
    onTimeInterval(handler, timeIntervalInMinutes = 60, backfillTimeIntervalInMinutes = 240, fetchConfig) {
        return this.onInterval(handler, {
            recentInterval: timeIntervalInMinutes,
            backfillInterval: backfillTimeIntervalInMinutes
        }, undefined, this.objectType.getSignature(), fetchConfig);
    }
    onCheckpointInterval(handler, checkpointInterval = 100000, backfillCheckpointInterval = 400000, fetchConfig) {
        return this.onInterval(handler, undefined, { recentInterval: checkpointInterval, backfillInterval: backfillCheckpointInterval }, this.objectType.qname, fetchConfig);
    }
}
export class SuiWrappedObjectProcessor extends SuiBaseObjectOrAddressProcessorInternal {
    static bind(options) {
        return new SuiWrappedObjectProcessor({
            address: options.objectId,
            network: options.network,
            startCheckpoint: options.startCheckpoint,
            endCheckpoint: options.endCheckpoint,
            ownerType: MoveOwnerType.WRAPPED_OBJECT,
            baseLabels: options.baseLabels
        });
    }
    async doHandle(handler, data, ctx) {
        return handler(data.rawObjects.map((o) => JSON.parse(o)), ctx);
    }
}
//# sourceMappingURL=sui-object-processor.js.map