import { EventEmitter } from "@visactor/vutils";

export class VTableSheetEventBus {
    constructor(options = {}) {
        this.performanceMetrics = new Map, this.wrappedCallbacks = new WeakMap, this.options = Object.assign({
            enableErrorBoundary: !0,
            enablePerformanceMonitoring: !1,
            maxListeners: 100
        }, options), this.eventBus = new EventEmitter, this.options.maxListeners && "function" == typeof this.eventBus.setMaxListeners && this.eventBus.setMaxListeners(this.options.maxListeners);
    }
    on(eventType, callback) {
        const wrappedCallback = this.options.enableErrorBoundary ? this.createErrorBoundary(callback, eventType) : callback;
        this.eventBus.on(eventType, wrappedCallback), this.wrappedCallbacks.set(callback, wrappedCallback);
    }
    off(eventType, callback) {
        if (callback) {
            const wrappedCallback = this.wrappedCallbacks.get(callback);
            wrappedCallback ? (this.eventBus.off(eventType, wrappedCallback), this.wrappedCallbacks.delete(callback)) : this.eventBus.off(eventType, callback);
        } else this.eventBus.off(eventType), this.wrappedCallbacks = new WeakMap;
    }
    emit(eventType, ...args) {
        const startTime = this.options.enablePerformanceMonitoring ? performance.now() : 0;
        try {
            this.eventBus.emit(eventType, ...args);
        } catch (error) {
            if (!this.options.enableErrorBoundary) throw error;
        } finally {
            if (this.options.enablePerformanceMonitoring) {
                const duration = performance.now() - startTime;
                this.recordPerformanceMetric(eventType, duration);
            }
        }
    }
    once(eventType, callback) {
        const wrappedCallback = this.options.enableErrorBoundary ? this.createErrorBoundary(callback, eventType, !0) : callback;
        this.eventBus.once(eventType, wrappedCallback), this.wrappedCallbacks.set(callback, wrappedCallback);
    }
    removeAllListeners(eventType) {
        eventType ? (this.eventBus.removeAllListeners(eventType), this.performanceMetrics.delete(eventType)) : (this.eventBus.removeAllListeners(), 
        this.performanceMetrics.clear());
    }
    listenerCount(eventType) {
        return this.eventBus.listenerCount(eventType);
    }
    getPerformanceMetrics(eventType) {
        if (eventType) {
            const metrics = new Map, eventMetrics = this.performanceMetrics.get(eventType);
            return eventMetrics && metrics.set(eventType, [ ...eventMetrics ]), metrics;
        }
        return new Map(this.performanceMetrics);
    }
    getEventEmitter() {
        return this.eventBus;
    }
    createErrorBoundary(callback, eventType, isOnce = !1) {
        return (...args) => {
            try {
                callback(...args);
            } catch (error) {}
        };
    }
    recordPerformanceMetric(eventType, duration) {
        this.performanceMetrics.has(eventType) || this.performanceMetrics.set(eventType, []);
        const metrics = this.performanceMetrics.get(eventType);
        metrics.push(duration), metrics.length > 100 && metrics.shift();
    }
}