"use strict";
/**
 * WebSocket Handler (Phase 04)
 *
 * Manages WebSocket connections, broadcasts file changes, and handles client messages.
 * Also broadcasts project selection events during OAuth flows.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.setupWebSocket = void 0;
const ws_1 = require("ws");
const file_watcher_1 = require("./file-watcher");
const project_selection_handler_1 = require("../cliproxy/auth/project-selection-handler");
const device_code_handler_1 = require("../cliproxy/auth/device-code-handler");
const logging_1 = require("../services/logging");
const logger = (0, logging_1.createLogger)('web-server:websocket');
function setupWebSocket(wss) {
    // Track connected clients
    const clients = new Set();
    // Broadcast message to all clients
    function broadcast(message) {
        const data = JSON.stringify(message);
        clients.forEach((client) => {
            if (client.readyState === ws_1.WebSocket.OPEN) {
                client.send(data);
            }
        });
    }
    // Handle new connections
    wss.on('connection', (ws) => {
        clients.add(ws);
        logger.info('client.connected', 'WebSocket client connected', { clients: clients.size });
        // Send welcome message
        ws.send(JSON.stringify({ type: 'connected', timestamp: Date.now() }));
        // Handle client messages
        ws.on('message', (data) => {
            try {
                const message = JSON.parse(data.toString());
                handleClientMessage(ws, message);
            }
            catch {
                logger.warn('message.invalid', 'WebSocket client sent invalid JSON');
            }
        });
        // Handle disconnect
        ws.on('close', () => {
            clients.delete(ws);
            logger.info('client.disconnected', 'WebSocket client disconnected', {
                clients: clients.size,
            });
        });
        ws.on('error', (err) => {
            logger.warn('client.error', 'WebSocket client error', { message: err.message });
            clients.delete(ws);
        });
    });
    // Handle incoming client messages
    function handleClientMessage(ws, message) {
        switch (message.type) {
            case 'ping':
                ws.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
                break;
            case 'subscribe':
                // Future: selective subscriptions
                break;
            default:
                logger.warn('message.unknown', 'WebSocket client sent unknown message type', {
                    type: String(message.type),
                });
        }
    }
    // Setup file watcher
    const watcher = (0, file_watcher_1.createFileWatcher)((event) => {
        logger.debug('file.changed', 'Dashboard file watcher detected a change', { ...event });
        broadcast({
            type: event.type,
            path: event.path,
            timestamp: event.timestamp,
        });
    });
    // Listen for project selection events and broadcast to clients
    const handleProjectSelectionRequired = (prompt) => {
        logger.info('project-selection.required', 'Broadcasting project selection prompt', {
            sessionId: prompt.sessionId,
        });
        broadcast({
            type: 'projectSelectionRequired',
            ...prompt,
            timestamp: Date.now(),
        });
    };
    const handleProjectSelectionTimeout = (sessionId) => {
        logger.info('project-selection.timeout', 'Project selection prompt timed out', { sessionId });
        broadcast({
            type: 'projectSelectionTimeout',
            sessionId,
            timestamp: Date.now(),
        });
    };
    const handleProjectSelectionSubmitted = (response) => {
        logger.info('project-selection.submitted', 'Project selection submitted', response);
        broadcast({
            type: 'projectSelectionSubmitted',
            ...response,
            timestamp: Date.now(),
        });
    };
    // Listen for device code events and broadcast to clients
    const handleDeviceCodeReceived = (prompt) => {
        logger.info('device-code.received', 'Broadcasting device code prompt', {
            sessionId: prompt.sessionId,
        });
        broadcast({
            type: 'deviceCodeReceived',
            ...prompt,
            timestamp: Date.now(),
        });
    };
    const handleDeviceCodeCompleted = (sessionId) => {
        logger.info('device-code.completed', 'Device code auth completed', { sessionId });
        broadcast({
            type: 'deviceCodeCompleted',
            sessionId,
            timestamp: Date.now(),
        });
    };
    const handleDeviceCodeFailed = (data) => {
        logger.warn('device-code.failed', 'Device code auth failed', data);
        broadcast({
            type: 'deviceCodeFailed',
            ...data,
            timestamp: Date.now(),
        });
    };
    const handleDeviceCodeExpired = (sessionId) => {
        logger.info('device-code.expired', 'Device code expired', { sessionId });
        broadcast({
            type: 'deviceCodeExpired',
            sessionId,
            timestamp: Date.now(),
        });
    };
    // Subscribe to project selection events
    project_selection_handler_1.projectSelectionEvents.on('selection:required', handleProjectSelectionRequired);
    project_selection_handler_1.projectSelectionEvents.on('selection:timeout', handleProjectSelectionTimeout);
    project_selection_handler_1.projectSelectionEvents.on('selection:submitted', handleProjectSelectionSubmitted);
    // Subscribe to device code events
    device_code_handler_1.deviceCodeEvents.on('deviceCode:received', handleDeviceCodeReceived);
    device_code_handler_1.deviceCodeEvents.on('deviceCode:completed', handleDeviceCodeCompleted);
    device_code_handler_1.deviceCodeEvents.on('deviceCode:failed', handleDeviceCodeFailed);
    device_code_handler_1.deviceCodeEvents.on('deviceCode:expired', handleDeviceCodeExpired);
    // Cleanup function
    const cleanup = () => {
        watcher.close();
        // Unsubscribe from project selection events
        project_selection_handler_1.projectSelectionEvents.off('selection:required', handleProjectSelectionRequired);
        project_selection_handler_1.projectSelectionEvents.off('selection:timeout', handleProjectSelectionTimeout);
        project_selection_handler_1.projectSelectionEvents.off('selection:submitted', handleProjectSelectionSubmitted);
        // Unsubscribe from device code events
        device_code_handler_1.deviceCodeEvents.off('deviceCode:received', handleDeviceCodeReceived);
        device_code_handler_1.deviceCodeEvents.off('deviceCode:completed', handleDeviceCodeCompleted);
        device_code_handler_1.deviceCodeEvents.off('deviceCode:failed', handleDeviceCodeFailed);
        device_code_handler_1.deviceCodeEvents.off('deviceCode:expired', handleDeviceCodeExpired);
        clients.forEach((client) => {
            client.close(1001, 'Server shutting down');
        });
        clients.clear();
    };
    return { cleanup };
}
exports.setupWebSocket = setupWebSocket;
//# sourceMappingURL=websocket.js.map