import { blockReorgDepth as e } from "../../../constants/reorg-depths.constants.mjs";
import { Logger as t } from "../../../error-handling/logger.mjs";
import { getSequence as n, resolveSync as r } from "../../../functions/utils/resolve-sync.utils.mjs";
import { getProviderFromContract as i } from "../../../functions/utils/getSignerFromContract.mjs";
import { BlockchainEvent as a } from "../../BlockchainEvent/BlockchainEvent.mjs";
import { ethers as o } from "ethers";
//#region libs/shared/common/src/data-structures/event-service/evm/BlockchainEventEmitter.ts
var s = class {
	RETRY_MIN_PAGE_SIZE = 100;
	MAX_RETRIES = 20;
	_chainId;
	contract;
	depositOnChainUtxosContract;
	_latestBlockNumber;
	_initialBlockNumber;
	onEventsProcessed;
	eventProcessors = /* @__PURE__ */ new Set();
	maxPageSize;
	_isReady = !1;
	isServer;
	inProgress;
	eventsFetchingMutex;
	constructor(e, t, n, r, i, a, o) {
		this.contract = t, this.depositOnChainUtxosContract = o, this._chainId = e, this._initialBlockNumber = n, this.maxPageSize = a, this.isServer = r, this.inProgress = !1, this.eventsFetchingMutex = i;
	}
	get latestBlockNumber() {
		return this._latestBlockNumber ?? this._initialBlockNumber;
	}
	get chainId() {
		return this._chainId;
	}
	get isReady() {
		return this._isReady;
	}
	syncFromAtMost(e) {
		(this._latestBlockNumber === void 0 || e < this._latestBlockNumber) && (this._latestBlockNumber = e);
	}
	advanceLatestBlockNumber(e) {
		e > (this._latestBlockNumber ?? this._initialBlockNumber) && (this._latestBlockNumber = e);
	}
	intervalClear() {
		this._isReady = !1, this.eventProcessors = /* @__PURE__ */ new Set(), this.clear();
	}
	async init() {
		if (this._isReady) throw Error("Already initialized");
		this._isReady = !0, await this.retrieveEvents(this.latestBlockNumber + 1), this.startUpdateListener();
	}
	requireReady() {
		if (!this._isReady) throw Error("Not ready");
	}
	async getEventsForSingleContract(e, t, n, r = 0) {
		try {
			return (await e.queryFilter("*", t, n)).filter((e) => e instanceof o.EventLog);
		} catch (i) {
			if (r < this.MAX_RETRIES && n - t > this.RETRY_MIN_PAGE_SIZE) {
				let i = Math.floor((t + n) / 2), a = await this.getEventsForSingleContract(e, t, i, r + 1), o = await this.getEventsForSingleContract(e, i + 1, n, r + 1);
				return [...a, ...o];
			}
			throw i;
		}
	}
	addEventProcessorFunction(e) {
		if (this._isReady) throw Error("Can't add event processor after event emitter initialized");
		this.eventProcessors.add(e);
	}
	async getEventsInRange(e, t) {
		let i = [], o = n(e, t, this.maxPageSize);
		await r(o.map(({ from: e, to: t }) => async () => {
			let n = await this.getEventsForSingleContract(this.contract, e, t);
			i.push(...n);
		}));
		let s = this.depositOnChainUtxosContract;
		return s && await r(o.map(({ from: e, to: t }) => async () => {
			let n = await this.getEventsForSingleContract(s, e, t);
			i.push(...n);
		})), i.map((e) => a.fromEthers(e));
	}
	async getLastBlockNumberForEventRequest() {
		let t = await i(this.contract).getBlockNumber();
		if (!this.isServer) return t;
		let { chainId: n } = await i(this.contract).getNetwork();
		return Math.max(this.latestBlockNumber, t - e[Number(n)] + 1);
	}
	async retrieveEvents(e, n = !1) {
		return this.requireReady(), await this.eventsFetchingMutex.runExclusive(async () => {
			try {
				if (this.inProgress && !n) return !1;
				this.inProgress = !0;
				let t = await this.getLastBlockNumberForEventRequest();
				if (t < e) return this.inProgress = !1, !1;
				let r = await this.getEventsInRange(e, t);
				return await this.processEvents(r, t), this._latestBlockNumber = t, this.inProgress = !1, !0;
			} catch (e) {
				return t.error("retrieveEvents error", e), this.inProgress = !1, !1;
			}
		});
	}
	async processEvents(e, t) {
		let n = (await Promise.all([...this.eventProcessors].map((n) => n(e, t)))).reduce((e, t) => e + t, 0);
		this.onEventsProcessed?.(n);
	}
};
//#endregion
export { s as BlockchainEventEmitter };
