/**
 * TUI WebSocket Server
 * Auto-starts when CLI launches with TUI mode
 * Provides bidirectional communication between MK3 TUI (Rust) and Node.js backend
 */
import { WebSocketServer, WebSocket } from 'ws';
import { EventEmitter } from 'events';
import { DEFAULT_TUI_WS_PORT } from './tui-defaults.js';
/**
 * TUI runs as a child with stdio: 'inherit'. stdout must stay clean for the terminal UI —
 * never use console.log here or log lines will splice into ratatui output (broken layout).
 */
function tuiLogInfo(message, detail) {
    const line = detail ? `[4Runr] ${message} ${detail}\n` : `[4Runr] ${message}\n`;
    process.stderr.write(line);
}
function tuiLogError(message, err) {
    const suffix = err instanceof Error ? err.message : err !== undefined ? String(err) : '';
    const line = suffix ? `[4Runr] ${message}: ${suffix}\n` : `[4Runr] ${message}\n`;
    process.stderr.write(line);
}
export class TUIServer extends EventEmitter {
    wss = null;
    clients = new Set();
    port;
    isRunning = false;
    constructor(port = DEFAULT_TUI_WS_PORT) {
        super();
        this.port = port;
    }
    getListenPort() {
        return this.port;
    }
    /**
     * Start the WebSocket server
     */
    start() {
        return new Promise((resolve, reject) => {
            if (this.isRunning) {
                resolve();
                return;
            }
            this.wss = new WebSocketServer({ port: this.port });
            this.wss.once('error', (error) => {
                tuiLogError('Error', error);
                try {
                    this.wss?.close();
                }
                catch {
                    /* ignore */
                }
                this.wss = null;
                reject(error);
            });
            this.wss.once('listening', () => {
                tuiLogInfo(`WebSocket server listening on ws://localhost:${this.port}`);
                this.isRunning = true;
                resolve();
            });
            this.wss.on('connection', (ws) => {
                tuiLogInfo('Client connected');
                this.clients.add(ws);
                ws.on('message', (data) => {
                    this.handleMessage(ws, data);
                });
                ws.on('close', () => {
                    tuiLogInfo('Client disconnected');
                    this.clients.delete(ws);
                });
                ws.on('error', (error) => {
                    tuiLogError('Client error', error);
                    this.clients.delete(ws);
                });
                // Send welcome message
                this.sendResponse(ws, 'connection', {
                    success: true,
                    data: {
                        message: 'Connected to 4Runr OS',
                        version: '1.0.0',
                        timestamp: new Date().toISOString(),
                    },
                });
            });
        });
    }
    /**
     * Stop the WebSocket server
     */
    stop() {
        return new Promise((resolve) => {
            if (!this.wss || !this.isRunning) {
                resolve();
                return;
            }
            // Close all client connections
            this.clients.forEach((client) => {
                client.close();
            });
            this.clients.clear();
            this.wss.close(() => {
                tuiLogInfo('WebSocket server stopped');
                this.isRunning = false;
                resolve();
            });
        });
    }
    /**
     * Handle incoming message from TUI
     */
    handleMessage(ws, data) {
        try {
            const raw = JSON.parse(data.toString());
            if (!raw || typeof raw !== 'object') {
                this.sendError(ws, 'unknown', 'Invalid message: expected object');
                return;
            }
            const message = raw;
            // Validate message structure
            if (!message.type || message.type !== 'command') {
                this.sendError(ws, message.id || 'unknown', 'Invalid message type');
                return;
            }
            const payload = message.payload;
            if (!payload || typeof payload !== 'object' || typeof payload.command !== 'string') {
                this.sendError(ws, message.id || 'unknown', 'Missing command');
                return;
            }
            const cmd = payload.command;
            if (process.env.TUI_WS_VERBOSE === '1' || process.env.TUI_WS_VERBOSE === 'true') {
                tuiLogInfo(`Received command: ${cmd}`);
            }
            // Emit command event for handlers to process
            this.emit('command', {
                ws,
                id: message.id,
                command: cmd,
                data: payload.data,
            });
        }
        catch (error) {
            const msg = error instanceof Error ? error.message : String(error);
            tuiLogError('Error parsing message', error);
            this.sendError(ws, 'unknown', `Invalid JSON: ${msg}`);
        }
    }
    /**
     * Send response back to TUI
     */
    sendResponse(ws, requestId, payload) {
        const response = {
            type: 'response',
            id: requestId,
            timestamp: new Date().toISOString(),
            payload,
        };
        this.sendMessage(ws, response);
    }
    /**
     * Send error response back to TUI
     */
    sendError(ws, requestId, errorMessage) {
        const response = {
            type: 'response',
            id: requestId,
            timestamp: new Date().toISOString(),
            payload: {
                success: false,
                error: errorMessage,
            },
        };
        this.sendMessage(ws, response);
    }
    /**
     * Broadcast event to all connected clients
     */
    broadcastEvent(event, data) {
        const eventMessage = {
            type: 'event',
            timestamp: new Date().toISOString(),
            payload: {
                event,
                data,
            },
        };
        this.clients.forEach((client) => {
            if (client.readyState === WebSocket.OPEN) {
                this.sendMessage(client, eventMessage);
            }
        });
    }
    /**
     * Send event to specific client
     */
    sendEvent(ws, event, data) {
        const eventMessage = {
            type: 'event',
            timestamp: new Date().toISOString(),
            payload: {
                event,
                data,
            },
        };
        this.sendMessage(ws, eventMessage);
    }
    /**
     * Send message to client
     */
    sendMessage(ws, message) {
        if (ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify(message));
        }
    }
    /**
     * Get number of connected clients
     */
    getClientCount() {
        return this.clients.size;
    }
    /**
     * Check if server is running
     */
    isServerRunning() {
        return this.isRunning;
    }
}
// Singleton instance
let tuiServerInstance = null;
/**
 * Get or create TUI server instance
 */
export function getTUIServer(port = DEFAULT_TUI_WS_PORT) {
    if (!tuiServerInstance || tuiServerInstance.getListenPort() !== port) {
        tuiServerInstance = new TUIServer(port);
    }
    return tuiServerInstance;
}
/**
 * Start TUI server if not already running
 */
export async function startTUIServer(port = DEFAULT_TUI_WS_PORT) {
    const server = getTUIServer(port);
    if (!server.isServerRunning()) {
        await server.start();
    }
    return server;
}
/**
 * Stop TUI server
 */
export async function stopTUIServer() {
    if (tuiServerInstance) {
        await tuiServerInstance.stop();
        tuiServerInstance = null;
    }
}
//# sourceMappingURL=tui-server.js.map