// ===== INTERNAL DATA STRUCTURES FOR MEMPOOL AGGREGATE =====
/**
 * Maps tx hash → internal numeric id (memory-efficient).
 * Also provides reverse lookup: id → hash.
 */
export class TxHashIndex {
    constructor() {
        this.hashToId = new Map();
        this.idToHash = new Map();
        this.nextId = 0;
    }
    add(hash) {
        if (this.hashToId.has(hash))
            return this.hashToId.get(hash);
        const id = this.nextId++;
        this.hashToId.set(hash, id);
        this.idToHash.set(id, hash);
        return id;
    }
    getByHash(hash) {
        return this.hashToId.get(hash);
    }
    getById(id) {
        return this.idToHash.get(id);
    }
    has(hash) {
        return this.hashToId.has(hash);
    }
    hasId(id) {
        return this.idToHash.has(id);
    }
    remove(hash) {
        const id = this.hashToId.get(hash);
        if (id !== undefined) {
            this.hashToId.delete(hash);
            this.idToHash.delete(id);
        }
    }
    size() {
        return this.hashToId.size;
    }
    clear() {
        this.hashToId.clear();
        this.idToHash.clear();
    }
    __getMap() {
        return this.idToHash;
    }
    __setMap(m) {
        this.idToHash = m;
        this.hashToId = new Map([...m.entries()].map(([id, hash]) => [hash, id]));
        this.nextId = m.size > 0 ? Math.max(...m.keys()) + 1 : 0;
    }
}
/**
 * Maps internal id → MempoolTxMetadata.
 * Stores only metadata (no input/calldata).
 */
export class MetadataStore {
    constructor() {
        this.store = new Map();
    }
    get(id) {
        return this.store.get(id);
    }
    set(id, meta) {
        this.store.set(id, meta);
    }
    has(id) {
        return this.store.has(id);
    }
    remove(id) {
        this.store.delete(id);
    }
    size() {
        return this.store.size;
    }
    __getMap() {
        return this.store;
    }
    __setMap(m) {
        this.store = m;
    }
}
export class LoadTracker {
    constructor() {
        this.store = new Map();
    }
    add(id, entry) {
        this.store.set(id, entry);
    }
    has(id) {
        return this.store.has(id);
    }
    get(id) {
        return this.store.get(id);
    }
    remove(id) {
        this.store.delete(id);
    }
    count() {
        return this.store.size;
    }
    __getMap() {
        return this.store;
    }
    __setMap(m) {
        this.store = m;
    }
}
/**
 * Maps providerName → Set<internal id> for per-provider tracking.
 */
export class ProviderTxMap {
    constructor() {
        this.store = new Map();
    }
    add(provider, id) {
        if (!this.store.has(provider))
            this.store.set(provider, new Set());
        this.store.get(provider).add(id);
    }
    get(provider) {
        return this.store.get(provider);
    }
    providers() {
        return Array.from(this.store.keys());
    }
    remove(provider, id) {
        this.store.get(provider)?.delete(id);
    }
    removeId(id) {
        for (const set of this.store.values())
            set.delete(id);
    }
    __getMap() {
        return this.store;
    }
    __setMap(m) {
        this.store = m;
    }
}
/**
 * Nonce-based index for replacement detection.
 * Maps "${from}:${nonce}" → internal id.
 * EVM-specific — no equivalent in bitcoin.
 */
export class NonceIndex {
    constructor() {
        this.store = new Map();
    }
    key(from, nonce) {
        return `${from.toLowerCase()}:${nonce}`;
    }
    set(from, nonce, id) {
        this.store.set(this.key(from, nonce), id);
    }
    get(from, nonce) {
        return this.store.get(this.key(from, nonce));
    }
    remove(from, nonce) {
        this.store.delete(this.key(from, nonce));
    }
    removeById(id) {
        for (const [k, v] of this.store.entries()) {
            if (v === id) {
                this.store.delete(k);
                return;
            }
        }
    }
    __getMap() {
        return this.store;
    }
    __setMap(m) {
        this.store = m;
    }
}
/**
 * Adaptive batch sizer: adjusts per-provider fetch batch size
 * based on timing ratio (same algorithm as bitcoin).
 */
export class BatchSizer {
    constructor(defaultSize = 100, minSize = 10, maxSize = 1000) {
        this.sizes = new Map();
        this.defaultSize = defaultSize;
        this.minSize = minSize;
        this.maxSize = maxSize;
    }
    get(provider) {
        return this.sizes.get(provider) ?? this.defaultSize;
    }
    /** ratio > 1 → current was slower → shrink. ratio < 1 → faster → grow. */
    tune(provider, ratio) {
        const cur = this.get(provider);
        let next;
        if (ratio > 1.2)
            next = Math.max(this.minSize, Math.round(cur * 0.75));
        else if (ratio < 0.8)
            next = Math.min(this.maxSize, Math.round(cur * 1.25));
        else
            next = cur;
        this.sizes.set(provider, next);
    }
    clear() {
        this.sizes.clear();
    }
}
