"use strict";
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
 * WASM Plugin Delta Subscription Management
 *
 * Manages delta subscriptions for WASM plugins, including:
 * - Subscription pattern matching
 * - Buffering during hot-reload
 * - Subscription state preservation across reloads
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WasmSubscriptionManager = void 0;
exports.getSubscriptionManager = getSubscriptionManager;
exports.initializeSubscriptionManager = initializeSubscriptionManager;
exports.resetSubscriptionManager = resetSubscriptionManager;
const debug_1 = __importDefault(require("debug"));
const debug = (0, debug_1.default)('signalk:wasm:subscriptions');
class WasmSubscriptionManager {
    // Active subscriptions by plugin ID
    subscriptions = new Map();
    // Buffered deltas during reload
    buffers = new Map();
    // Buffering state
    buffering = new Set();
    /**
     * Register a delta subscription for a plugin
     */
    register(pluginId, pattern, callback) {
        if (!this.subscriptions.has(pluginId)) {
            this.subscriptions.set(pluginId, []);
        }
        const subscription = {
            pluginId,
            pattern,
            callback
        };
        this.subscriptions.get(pluginId).push(subscription);
        debug(`Registered subscription for ${pluginId}: ${pattern}`);
    }
    /**
     * Unregister all subscriptions for a plugin
     */
    unregister(pluginId) {
        const count = this.subscriptions.get(pluginId)?.length || 0;
        this.subscriptions.delete(pluginId);
        debug(`Unregistered ${count} subscriptions for ${pluginId}`);
    }
    /**
     * Get all subscriptions for a plugin
     */
    getSubscriptions(pluginId) {
        return this.subscriptions.get(pluginId) || [];
    }
    /**
     * Check if a delta path matches a subscription pattern
     */
    matchesPattern(path, pattern) {
        if (pattern === '*') {
            return true;
        }
        // Simple glob-style matching
        // "navigation.*" matches "navigation.position", "navigation.courseOverGroundTrue", etc.
        const regexPattern = pattern
            .replace(/[\\^$+?()[\]{}|]/g, '\\$&')
            .replace(/\./g, '\\.')
            .replace(/\*/g, '.*');
        const regex = new RegExp(`^${regexPattern}$`);
        return regex.test(path);
    }
    /**
     * Route a delta to subscribed plugins
     */
    routeDelta(delta) {
        for (const [pluginId, subs] of this.subscriptions) {
            // Check if buffering for this plugin
            if (this.buffering.has(pluginId)) {
                this.bufferDelta(pluginId, delta);
                continue;
            }
            // Check if any subscription matches delta paths
            for (const sub of subs) {
                let matches = false;
                for (const update of delta.updates) {
                    for (const pathValue of update.values) {
                        if (this.matchesPattern(pathValue.path, sub.pattern)) {
                            matches = true;
                            break;
                        }
                    }
                    if (matches)
                        break;
                }
                if (matches) {
                    try {
                        sub.callback(delta);
                    }
                    catch (error) {
                        debug(`Error in subscription callback for ${pluginId}:`, error);
                    }
                    break; // Only call once per plugin per delta
                }
            }
        }
    }
    /**
     * Start buffering deltas for a plugin (during reload)
     */
    startBuffering(pluginId) {
        debug(`Started buffering deltas for ${pluginId}`);
        this.buffering.add(pluginId);
        this.buffers.set(pluginId, []);
    }
    /**
     * Stop buffering and return buffered deltas
     */
    stopBuffering(pluginId) {
        debug(`Stopped buffering deltas for ${pluginId}`);
        this.buffering.delete(pluginId);
        const buffered = this.buffers.get(pluginId) || [];
        this.buffers.delete(pluginId);
        debug(`Returning ${buffered.length} buffered deltas for ${pluginId}`);
        return buffered;
    }
    /**
     * Buffer a delta for a plugin
     */
    bufferDelta(pluginId, delta) {
        if (!this.buffers.has(pluginId)) {
            this.buffers.set(pluginId, []);
        }
        const buffer = this.buffers.get(pluginId);
        buffer.push(delta);
        // Limit buffer size to prevent memory issues
        const MAX_BUFFER_SIZE = 1000;
        if (buffer.length > MAX_BUFFER_SIZE) {
            buffer.shift(); // Remove oldest
            debug(`Buffer overflow for ${pluginId}, dropped oldest delta`);
        }
    }
    /**
     * Redirect delta routing to buffer for a plugin
     */
    redirectToBuffer(pluginId) {
        this.startBuffering(pluginId);
    }
    /**
     * Restore normal delta routing for a plugin
     */
    restore(pluginId) {
        this.stopBuffering(pluginId);
    }
    /**
     * Replay buffered deltas to a plugin's callback
     */
    replayBuffered(pluginId, callback) {
        const buffered = this.buffers.get(pluginId) || [];
        debug(`Replaying ${buffered.length} buffered deltas to ${pluginId}`);
        for (const delta of buffered) {
            try {
                callback(delta);
            }
            catch (error) {
                debug(`Error replaying delta to ${pluginId}:`, error);
            }
        }
        // Clear buffer after replay
        this.buffers.delete(pluginId);
    }
    /**
     * Get statistics about subscriptions
     */
    getStats() {
        let totalSubscriptions = 0;
        for (const subs of this.subscriptions.values()) {
            totalSubscriptions += subs.length;
        }
        let bufferedDeltas = 0;
        for (const buffer of this.buffers.values()) {
            bufferedDeltas += buffer.length;
        }
        return {
            totalSubscriptions,
            activePlugins: this.subscriptions.size,
            bufferingPlugins: this.buffering.size,
            bufferedDeltas
        };
    }
    /**
     * Clear all subscriptions and buffers
     */
    clear() {
        this.subscriptions.clear();
        this.buffers.clear();
        this.buffering.clear();
        debug('Cleared all subscriptions and buffers');
    }
}
exports.WasmSubscriptionManager = WasmSubscriptionManager;
// Global singleton instance
let subscriptionManager = null;
/**
 * Get the global subscription manager
 */
function getSubscriptionManager() {
    if (!subscriptionManager) {
        subscriptionManager = new WasmSubscriptionManager();
    }
    return subscriptionManager;
}
/**
 * Initialize the subscription manager
 */
function initializeSubscriptionManager() {
    if (subscriptionManager) {
        debug('Subscription manager already initialized');
        return subscriptionManager;
    }
    subscriptionManager = new WasmSubscriptionManager();
    debug('Subscription manager initialized');
    return subscriptionManager;
}
/**
 * Reset the subscription manager singleton (for hotplug support)
 * This should be called after shutdown to allow re-initialization
 */
function resetSubscriptionManager() {
    debug('Resetting subscription manager singleton');
    subscriptionManager = null;
}
//# sourceMappingURL=wasm-subscriptions.js.map