/**
 * Centralized polling manager with subscription pattern.
 * Reduces duplicate intervals and provides pause/resume functionality.
 *
 * Usage:
 *   PollingManager.subscribe('my-id', myCallback, 500);
 *   PollingManager.unsubscribe('my-id');
 *   PollingManager.pause();
 *   PollingManager.resume();
 */
const PollingManager = {
    subscribers: new Map(),
    intervals: new Map(),
    paused: false,

    /**
     * Subscribe a callback to be polled at a specific interval.
     * @param {string} id - Unique identifier for this subscription
     * @param {Function} callback - Function to call on each tick
     * @param {number} intervalMs - Polling interval in milliseconds (default: 500)
     */
    subscribe(id, callback, intervalMs = 500) {
        this.subscribers.set(id, { callback, intervalMs, lastRun: 0 });

        // Create interval for this polling rate if it doesn't exist
        if (!this.intervals.has(intervalMs)) {
            const intervalId = setInterval(() => this._tick(intervalMs), intervalMs);
            this.intervals.set(intervalMs, intervalId);
        }
    },

    /**
     * Unsubscribe a callback from polling.
     * @param {string} id - The subscription ID to remove
     */
    unsubscribe(id) {
        const sub = this.subscribers.get(id);
        if (!sub) return;

        const intervalMs = sub.intervalMs;
        this.subscribers.delete(id);

        // Clean up interval if no more subscribers at this rate
        const hasOtherSubscribers = Array.from(this.subscribers.values())
            .some(s => s.intervalMs === intervalMs);

        if (!hasOtherSubscribers && this.intervals.has(intervalMs)) {
            clearInterval(this.intervals.get(intervalMs));
            this.intervals.delete(intervalMs);
        }
    },

    /**
     * Pause all polling. Callbacks will not be executed while paused.
     */
    pause() {
        this.paused = true;
    },

    /**
     * Resume polling after a pause.
     */
    resume() {
        this.paused = false;
    },

    /**
     * Check if polling is currently paused.
     * @returns {boolean}
     */
    isPaused() {
        return this.paused;
    },

    /**
     * Internal tick handler - executes all callbacks for the given interval.
     * @param {number} intervalMs - The interval rate to process
     * @private
     */
    _tick(intervalMs) {
        if (this.paused) return;

        this.subscribers.forEach((sub, id) => {
            if (sub.intervalMs === intervalMs) {
                try {
                    sub.callback();
                } catch (e) {
                    console.error(`Polling error for '${id}':`, e);
                }
            }
        });
    },

    /**
     * Get current subscriber count (useful for debugging).
     * @returns {number}
     */
    getSubscriberCount() {
        return this.subscribers.size;
    },

    /**
     * List all active subscriptions (useful for debugging).
     * @returns {Array<{id: string, intervalMs: number}>}
     */
    listSubscriptions() {
        return Array.from(this.subscribers.entries()).map(([id, sub]) => ({
            id,
            intervalMs: sub.intervalMs
        }));
    }
};
