"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.IPCBridge = void 0;
const electron_1 = require("electron");
const events_1 = require("events");
const BackendManager_1 = require("../process-manager/BackendManager");
const ViewManager_1 = require("../view-manager/ViewManager");
const crypto_1 = require("crypto");
const CommandRegistry_1 = require("./CommandRegistry");
const EventSubscriberManager_1 = require("./EventSubscriberManager");
const PermissionRegistry_1 = require("./PermissionRegistry");
const tsyringe_1 = require("tsyringe");
const EventHandler_1 = require("./EventHandler");
/**
 * IPCBridge
 *
 * Central communication hub for IPC messages between:
 * - Main process
 * - Utility processes (app backends)
 * - WebContentsViews (app frontends)
 */
let IPCBridge = class IPCBridge extends events_1.EventEmitter {
    backendManager;
    commandRegistry;
    viewManager;
    eventSubscribers;
    eventHandler;
    mainWindow = null;
    runningAppIds = new Set();
    pendingCommands = new Map();
    constructor(backendManager, commandRegistry, permissionRegistry, viewManager) {
        super();
        this.backendManager = backendManager;
        this.commandRegistry = commandRegistry;
        this.viewManager = viewManager;
        // Initialize event subscriber manager
        this.eventSubscribers = new EventSubscriberManager_1.EventSubscriberManager(viewManager);
        this.eventSubscribers.setBackendManager(this.backendManager);
        this.eventSubscribers.setPermissionRegistry(permissionRegistry);
        // Initialize and register EventHandler
        this.eventHandler = new EventHandler_1.EventHandler(this.eventSubscribers, viewManager);
        this.commandRegistry.registerManager(this.eventHandler);
        this.setupIPCHandlers();
        this.setupBackendMessageHandlers();
    }
    /**
     * Set the main window for shell communication
     */
    setMainWindow(window) {
        this.mainWindow = window;
    }
    /**
     * Get the main window instance
     */
    getMainWindow() {
        return this.mainWindow;
    }
    /**
     * Setup IPC handlers for renderer processes
     */
    setupIPCHandlers() {
        // Handle shell commands
        electron_1.ipcMain.handle("shell-command", async (event, command, args) => {
            // Build caller context for commands that need it
            const appId = this.viewManager.getAppIdByWebContentsId(event.sender.id);
            const argsWithContext = {
                ...args,
                _callerAppId: appId,
                _callerWebContentsId: event.sender.id,
            };
            return this.handleShellCommand(command, argsWithContext, appId);
        });
    }
    /**
     * Setup handlers for backend utility process messages
     */
    setupBackendMessageHandlers() {
        this.backendManager.on("backend-message", async ({ appId, message }) => {
            // Handle different message types from backend
            if (message.type === "shell-command") {
                // Backend requesting a shell command execution
                try {
                    // Inject caller context for backend commands
                    const argsWithContext = {
                        ...message.args,
                        _callerAppId: appId,
                    };
                    const result = await this.handleShellCommand(message.command, argsWithContext, appId);
                    // Send response back to backend
                    this.sendBackendResponse(appId, message.commandId, result);
                }
                catch (error) {
                    this.backendManager.sendMessage(appId, {
                        type: "shell-command-response",
                        commandId: message.commandId,
                        error: error instanceof Error ? error.message : String(error),
                    });
                }
            }
            else {
                console.warn(`Unknown backend message type from ${appId}:`, message.type);
            }
        });
    }
    /**
     * Helper to send response to backend
     */
    sendBackendResponse(appId, commandId, result) {
        this.backendManager.sendMessage(appId, {
            type: "shell-command-response",
            commandId,
            result,
        });
    }
    /**
     * Handle shell commands (app management, etc.)
     */
    async handleShellCommand(command, args, appId) {
        // Create a promise to wait for the command result
        const commandId = (0, crypto_1.randomUUID)();
        return new Promise((resolve, reject) => {
            const timeout = setTimeout(() => {
                console.error(`[IPCBridge] Command '${command}' (ID: ${commandId}) timed out after 10s`);
                this.pendingCommands.delete(commandId);
                reject(new Error(`Command '${command}' timed out`));
            }, 10000);
            this.pendingCommands.set(commandId, { resolve, reject, timeout });
            // Execute via CommandRegistry with appId for permission checking
            this.commandRegistry
                .execute(command, args, appId)
                .then((result) => {
                clearTimeout(timeout);
                this.pendingCommands.delete(commandId);
                resolve(result);
            })
                .catch((error) => {
                console.error(`[IPCBridge] Command '${command}' (ID: ${commandId}) failed:`, error);
                clearTimeout(timeout);
                this.pendingCommands.delete(commandId);
                reject(error);
            });
        });
    }
    /**
     * Provide running-app updates from the AppManager
     */
    updateRunningApps(appIds) {
        this.runningAppIds = new Set(appIds);
    }
    getRunningAppIds() {
        return Array.from(this.runningAppIds);
    }
    /**
     * Cleanup
     */
    destroy() {
        // Remove global IPC handlers
        electron_1.ipcMain.removeHandler("shell-command");
    }
};
exports.IPCBridge = IPCBridge;
exports.IPCBridge = IPCBridge = __decorate([
    (0, tsyringe_1.singleton)(),
    (0, tsyringe_1.injectable)(),
    __param(0, (0, tsyringe_1.inject)(BackendManager_1.BackendManager)),
    __param(1, (0, tsyringe_1.inject)(CommandRegistry_1.CommandRegistry)),
    __param(2, (0, tsyringe_1.inject)(PermissionRegistry_1.PermissionRegistry)),
    __param(3, (0, tsyringe_1.inject)((0, tsyringe_1.delay)(() => ViewManager_1.ViewManager))),
    __metadata("design:paramtypes", [BackendManager_1.BackendManager,
        CommandRegistry_1.CommandRegistry,
        PermissionRegistry_1.PermissionRegistry,
        ViewManager_1.ViewManager])
], IPCBridge);
//# sourceMappingURL=IPCBridge.js.map