"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventSubscriberManager = void 0;
const PermissionRegistry_1 = require("./PermissionRegistry");
class EventSubscriberManager {
    viewManager;
    backendManager;
    subscriptions = new Map();
    backendSubscriptions = new Map();
    internalSubscriptions = new Map();
    permissionRegistry;
    constructor(viewManager) {
        this.viewManager = viewManager;
    }
    /**
     * Set the backend manager for backend notifications
     */
    setBackendManager(backendManager) {
        this.backendManager = backendManager;
    }
    /**
     * Set the permission registry for permission checking
     */
    setPermissionRegistry(registry) {
        this.permissionRegistry = registry;
    }
    /**
     * Subscribe a view to an event
     */
    subscribe(viewId, eventName) {
        const viewInfo = this.viewManager.getViewInfo(viewId);
        if (!viewInfo) {
            console.warn(`Cannot subscribe: view ${viewId} not found`);
            return false;
        }
        // Check event permission if required
        const requiredPermission = (0, PermissionRegistry_1.getEventPermission)(eventName);
        if (requiredPermission && this.permissionRegistry) {
            if (!this.permissionRegistry.hasPermission(viewInfo.appId, requiredPermission)) {
                throw new Error(`Permission denied: ${requiredPermission} required to subscribe to ${eventName}`);
            }
        }
        if (!this.subscriptions.has(eventName)) {
            this.subscriptions.set(eventName, new Set());
        }
        this.subscriptions.get(eventName).add(viewId);
        console.log(`View ${viewId} (${viewInfo.appId}) subscribed to event: ${eventName}`);
        return true;
    }
    /**
     * Subscribe a backend to an event
     */
    subscribeBackend(appId, eventName) {
        // Check event permission if required
        const requiredPermission = (0, PermissionRegistry_1.getEventPermission)(eventName);
        if (requiredPermission && this.permissionRegistry) {
            if (!this.permissionRegistry.hasPermission(appId, requiredPermission)) {
                throw new Error(`Permission denied: ${requiredPermission} required to subscribe to ${eventName}`);
            }
        }
        if (!this.backendSubscriptions.has(eventName)) {
            this.backendSubscriptions.set(eventName, new Set());
        }
        this.backendSubscriptions.get(eventName).add(appId);
        console.log(`Backend (${appId}) subscribed to event: ${eventName}`);
        return true;
    }
    /**
     * Subscribe an internal callback (for managers) to an event
     * Unlike view subscriptions, these are in-process callbacks
     */
    subscribeInternal(event, callback) {
        if (!this.internalSubscriptions.has(event)) {
            this.internalSubscriptions.set(event, new Set());
        }
        this.internalSubscriptions
            .get(event)
            .add(callback);
        console.log(`Internal subscriber added for event: ${event}`);
    }
    /**
     * Unsubscribe a view from an event
     */
    unsubscribe(viewId, eventName) {
        const subscriptions = this.subscriptions.get(eventName);
        if (!subscriptions) {
            return false;
        }
        const result = subscriptions.delete(viewId);
        if (subscriptions.size === 0) {
            this.subscriptions.delete(eventName);
        }
        if (result) {
            console.log(`View ${viewId} unsubscribed from event: ${eventName}`);
        }
        return result;
    }
    /**
     * Unsubscribe a backend from an event
     */
    unsubscribeBackend(appId, eventName) {
        const subscriptions = this.backendSubscriptions.get(eventName);
        if (!subscriptions) {
            return false;
        }
        const result = subscriptions.delete(appId);
        if (subscriptions.size === 0) {
            this.backendSubscriptions.delete(eventName);
        }
        if (result) {
            console.log(`Backend (${appId}) unsubscribed from event: ${eventName}`);
        }
        return result;
    }
    /**
     * Get all views subscribed to an event
     */
    getSubscribedViews(eventName) {
        const subscriptions = this.subscriptions.get(eventName);
        return subscriptions ? Array.from(subscriptions) : [];
    }
    /**
     * Get all backends subscribed to an event
     */
    getSubscribedBackends(eventName) {
        const subscriptions = this.backendSubscriptions.get(eventName);
        return subscriptions ? Array.from(subscriptions) : [];
    }
    /**
     * Send event only to subscribed views, backends, and internal callbacks
     */
    notify(eventName, payload) {
        // Notify internal subscribers first
        const internalCallbacks = this.internalSubscriptions.get(eventName);
        if (internalCallbacks) {
            for (const callback of internalCallbacks) {
                try {
                    callback(payload);
                }
                catch (error) {
                    console.error(`Error in internal subscriber for ${eventName}:`, error);
                }
            }
        }
        // Notify view subscribers
        const subscribedViewIds = this.getSubscribedViews(eventName);
        for (const viewId of subscribedViewIds) {
            this.viewManager.sendToView(viewId, "shell-message", {
                type: eventName,
                payload,
            });
        }
        // Notify backend subscribers
        if (this.backendManager) {
            const subscribedBackends = this.getSubscribedBackends(eventName);
            for (const appId of subscribedBackends) {
                this.backendManager.sendMessage(appId, {
                    type: "shell-event",
                    eventName,
                    payload,
                });
            }
        }
    }
    /**
     * Send event to a specific subscribed view
     */
    notifyView(viewId, eventName, payload) {
        const subscriptions = this.subscriptions.get(eventName);
        if (!subscriptions || !subscriptions.has(viewId)) {
            return false;
        }
        return this.viewManager.sendToView(viewId, "shell-message", {
            type: eventName,
            payload,
        });
    }
    /**
     * Remove all subscriptions for a view
     */
    removeViewSubscriptions(viewId) {
        for (const [eventName, subscribers] of this.subscriptions.entries()) {
            if (subscribers.delete(viewId)) {
                if (subscribers.size === 0) {
                    this.subscriptions.delete(eventName);
                }
            }
        }
    }
    /**
     * Remove all subscriptions for a backend
     */
    removeBackendSubscriptions(appId) {
        for (const [eventName, subscribers,] of this.backendSubscriptions.entries()) {
            if (subscribers.delete(appId)) {
                if (subscribers.size === 0) {
                    this.backendSubscriptions.delete(eventName);
                }
            }
        }
    }
}
exports.EventSubscriberManager = EventSubscriberManager;
//# sourceMappingURL=EventSubscriberManager.js.map