"use strict";
/**
 * Binary Stream WebSocket Endpoints
 *
 * Provides WebSocket endpoints for high-frequency binary data streaming
 * from WASM plugins (radar spokes, AIS targets, etc.)
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.binaryStreamManager = void 0;
exports.initializeBinaryStreams = initializeBinaryStreams;
const debug_1 = __importDefault(require("debug"));
const ws_1 = __importDefault(require("ws"));
const binary_stream_manager_1 = require("./binary-stream-manager");
Object.defineProperty(exports, "binaryStreamManager", { enumerable: true, get: function () { return binary_stream_manager_1.binaryStreamManager; } });
const debug = (0, debug_1.default)('signalk:streams');
/**
 * Initialize binary stream WebSocket endpoints
 *
 * @param app - SignalK application instance
 */
function initializeBinaryStreams(app) {
    debug('initializeBinaryStreams called, app.server exists: %s', !!app.server);
    if (!app.server) {
        debug('HTTP server not available, skipping binary stream initialization');
        return;
    }
    debug('Initializing binary stream WebSocket endpoints');
    // Handle WebSocket upgrade requests for binary streams
    // Note: This listener is added to app.server which should be an HTTP server
    debug('Adding upgrade listener to server');
    app.server.on('upgrade', (request, socket, head) => {
        debug('Upgrade request received: %s, headers.host: %s', request.url, request.headers.host);
        try {
            const url = new URL(request.url, `http://${request.headers.host}`);
            const pathname = url.pathname;
            debug('Pathname: %s', pathname);
            // Match: /signalk/v2/api/streams/:streamId (support path segments in streamId)
            const streamMatch = pathname.match(/^\/signalk\/v2\/api\/streams\/(.+)$/);
            // Match: /signalk/v2/api/vessels/self/radars/:id/stream (convenience alias)
            const radarMatch = pathname.match(/^\/signalk\/v2\/api\/vessels\/self\/radars\/([^\/]+)\/stream$/);
            let streamId = null;
            if (streamMatch) {
                streamId = decodeURIComponent(streamMatch[1]);
                debug('Matched stream pattern: %s', streamId);
            }
            else if (radarMatch) {
                // Alias: map radar endpoint to radars/{radarId} stream
                const radarId = radarMatch[1];
                streamId = `radars/${radarId}`;
                debug('Matched radar stream pattern: %s', streamId);
            }
            else {
                // Not a binary stream endpoint, let other handlers process
                debug('No match for path, ignoring: %s', pathname);
                return;
            }
            debug('Processing WebSocket upgrade for stream: %s', streamId);
            // Authenticate the request (if security is enabled)
            let principal = { identifier: 'unknown' };
            const authRequest = request;
            // Check if security is enabled
            if (app.securityStrategy &&
                typeof app.securityStrategy.shouldAllowWrite === 'function') {
                try {
                    // Security is enabled, perform authentication
                    if (app.securityStrategy.authorizeWS) {
                        app.securityStrategy.authorizeWS(request);
                        principal = authRequest.skPrincipal || { identifier: 'unknown' };
                    }
                    else {
                        // Fallback: use shouldAllowWrite for basic auth check
                        if (!app.securityStrategy.shouldAllowWrite(request, 'streams')) {
                            throw new Error('Unauthorized');
                        }
                        principal = authRequest.skPrincipal || { identifier: 'unknown' };
                    }
                }
                catch (error) {
                    debug(`Authentication failed for stream ${streamId}: ${error}`);
                    socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
                    socket.destroy();
                    return;
                }
            }
            else {
                // Security is disabled, allow connection without authentication
                debug(`Security disabled, allowing unauthenticated connection to stream: ${streamId}`);
                principal = { identifier: 'unauthenticated' };
            }
            // Create WebSocket connection
            debug('Creating WebSocket server for stream: %s', streamId);
            const wss = new ws_1.default.Server({ noServer: true });
            wss.handleUpgrade(request, socket, head, (ws) => {
                debug('WebSocket connected to stream: %s', streamId);
                // Register client with stream manager
                binary_stream_manager_1.binaryStreamManager.addClient(streamId, ws, principal);
                ws.on('close', () => {
                    debug(`WebSocket disconnected from stream: ${streamId}`);
                    binary_stream_manager_1.binaryStreamManager.removeClient(streamId, ws);
                });
                ws.on('error', (err) => {
                    debug(`WebSocket error for stream ${streamId}: ${err}`);
                    binary_stream_manager_1.binaryStreamManager.removeClient(streamId, ws);
                });
                // Binary streams are one-way (server → client), ignore client messages
                ws.on('message', () => {
                    debug(`Ignoring message from client on binary stream ${streamId}`);
                });
            });
        }
        catch (error) {
            debug(`Error handling WebSocket upgrade: ${error}`);
            console.error('[signalk:streams] WebSocket upgrade error:', error);
            socket.write('HTTP/1.1 500 Internal Server Error\r\n\r\n');
            socket.destroy();
        }
    });
    debug('Binary stream WebSocket endpoints initialized');
}
//# sourceMappingURL=index.js.map