import { zeroAddress as e } from "../../constants/protocol.constants.mjs";
import { StorageKeys as t } from "../../types/cache.types.mjs";
import { getERC20Token as n, isNFTToken as r, overlayTokenWithRegistryData as i } from "../../functions/utils/erc20tokenFunctions.mjs";
import { lowerCaseIncludes as a } from "../../functions/utils/caseInsensitive.utils.mjs";
import { API as o } from "../../API/API.mjs";
import { Logger as s } from "../../error-handling/logger.mjs";
import { getStateKey as c } from "../../functions/utils/string.utils.mjs";
import { tokenVisibilityStorage as l } from "./token-visibility-db.mjs";
import { createJsonRpcProvider as u } from "../../functions/utils/create-provider.mjs";
import { EVENTS_INITIAL_BLOCKS as d } from "../../constants/events.constants.mjs";
import "../../constants/index.mjs";
import "../../functions/index.mjs";
import { ethers as f } from "ethers";
import { get as p, update as m } from "idb-keyval";
import { Mutex as h } from "async-mutex";
var g = new class {
	fetchedTokens = {};
	updateMutexes = {};
	transferEventTopic = f.id("Transfer(address,address,uint256)");
	chunkSize = 2e3;
	getMutex(e) {
		return this.updateMutexes[e] || (this.updateMutexes[e] = new h()), this.updateMutexes[e];
	}
	withRegistryOverlay(e, t) {
		let r = n(e.erc20TokenAddress, t);
		return r ? {
			...e,
			name: r.name,
			symbol: r.symbol,
			logoURI: r.logoURI,
			decimals: r.decimals
		} : e;
	}
	async getPublicTokens(e, n) {
		let r = c(n, e);
		return ((await p(t.EVENTS_PUBLIC_TOKENS))?.[r] || []).map((t) => i(t, e));
	}
	getFetchedTokens(e, t) {
		let n = c(t, e);
		return (this.fetchedTokens[n] || []).map((t) => i(t, e));
	}
	async fetchAndUpdatePublicTokens(e, n) {
		let r = c(e, n);
		await this.getMutex(r).runExclusive(async () => {
			try {
				let i = (await this.getPublicTokens(n, e)).map((e) => e.erc20TokenAddress), { toEvents: o, fromEvents: s, latestBlock: c } = await this.getEvents(e, n), u = [...o, ...s], { erc20Tokens: d } = await this.fetchPublicTokens(u, n, i), f = await l.hideSpamsAndFetchHiddenTokensAddresses(n, d), p = d.filter((e) => !a(f, e.erc20TokenAddress));
				await m(t.EVENTS_PUBLIC_TOKENS, (e = {}) => {
					let t = e[r] || [], n = t.map((e) => e.erc20TokenAddress), i = p.filter((e) => !a(n, e.erc20TokenAddress));
					t.push(...i);
					let c = this.updateTokenIds(s, o, t), l = {
						...e,
						[r]: c
					};
					return this.fetchedTokens = l, l;
				}), c && await this.updateLastProcessedBlock(n, e, c);
			} catch (e) {
				s.error("public tokens db error", e);
			}
		});
	}
	async getLastProcessedBlock(e, n) {
		return (await p(t.PUBLIC_TOKENS_LAST_PROCESSED_BLOCKS) || {})[c(n, e)] || d[e];
	}
	async updateLastProcessedBlock(e, n, r) {
		await m(t.PUBLIC_TOKENS_LAST_PROCESSED_BLOCKS, (t = {}) => {
			let i = c(n, e);
			return {
				...t,
				[i]: r
			};
		});
	}
	async getEvents(e, t) {
		try {
			let n = u(t), r = await this.getLastProcessedBlock(t, e) + 1, i = await n.getBlockNumber(), a = f.zeroPadValue(e.toLowerCase(), 32), o = [], s = [];
			for (let e = r; e <= i; e += this.chunkSize) {
				let t = Math.min(e + this.chunkSize - 1, i), r = {
					topics: [
						this.transferEventTopic,
						null,
						a
					],
					fromBlock: e,
					toBlock: t
				}, c = {
					topics: [
						this.transferEventTopic,
						a,
						null
					],
					fromBlock: e,
					toBlock: t
				}, [l, u] = await Promise.all([n.getLogs(r), n.getLogs(c)]);
				o.push(...l), s.push(...u);
			}
			return {
				toEvents: o,
				fromEvents: s,
				latestBlock: i
			};
		} catch (n) {
			return s.error("Error fetching events:", n, "chainId", t, "walletAddress", e), {
				toEvents: [],
				fromEvents: [],
				latestBlock: void 0
			};
		}
	}
	updateTokenIds(e, t, n) {
		let i = /* @__PURE__ */ new Map();
		return n.forEach((e) => {
			if (r(e) && e.tokenIds) {
				let t = e.erc20TokenAddress.toLowerCase();
				i.set(t, [...e.tokenIds]);
			}
		}), t.forEach((e) => {
			if (e.topics.length <= 3) return;
			let t = e.address.toLowerCase(), n = BigInt(e.topics[3]).toString();
			i.has(t) || i.set(t, []), i.get(t)?.push(n);
		}), e.forEach((e) => {
			if (e.topics.length <= 3) return;
			let t = e.address.toLowerCase(), n = i.get(t);
			if (n?.length) {
				let t = BigInt(e.topics[3]).toString(), r = n.indexOf(t);
				r !== -1 && n.splice(r, 1);
			}
		}), n.forEach((e) => {
			if (r(e)) {
				let t = e.erc20TokenAddress.toLowerCase(), n = i.get(t);
				e.tokenIds = n?.length && n.length > 0 ? n : void 0;
			}
		}), n;
	}
	async fetchPublicTokens(t, n, r) {
		try {
			let i = [e, ...new Set(t.map((e) => e.address))].filter((e) => e && !a(r, e));
			return i.length ? { erc20Tokens: (await o.tokensInfoCall(n, i)).filter((e) => !!e) } : { erc20Tokens: [] };
		} catch (e) {
			return s.error("Error fetching public tokens:", e), { erc20Tokens: [] };
		}
	}
}();
//#endregion
export { g as eventsPublicTokensDB };
