import { nanoid } from 'nanoid';
import { z } from 'zod';
import { bus } from '../ws-bus.js';
import { logger } from '../logger.js';
const ClientMessage = z.union([
    z.object({ type: z.literal('hello'), sessionId: z.string().optional() }),
    z.object({ type: z.literal('control'), action: z.string(), value: z.unknown().optional() }),
    z.object({ type: z.literal('pong') }),
]);
export async function wsRoutes(app) {
    app.get('/ws', { websocket: true }, (socket, req) => {
        const sessionId = req.query?.sessionId ?? nanoid(16);
        bus.attach(sessionId, socket);
        logger.info({ sessionId, remote: req.ip }, 'ws connected');
        socket.send(JSON.stringify({ type: 'welcome', sessionId }));
        const heartbeat = setInterval(() => {
            try {
                socket.send(JSON.stringify({ type: 'ping' }));
            }
            catch {
                clearInterval(heartbeat);
            }
        }, 30_000);
        socket.on('message', (raw) => {
            let parsed;
            try {
                parsed = JSON.parse(raw.toString());
            }
            catch {
                socket.send(JSON.stringify({ type: 'error', reason: 'invalid_json' }));
                return;
            }
            const result = ClientMessage.safeParse(parsed);
            if (!result.success) {
                socket.send(JSON.stringify({ type: 'error', reason: 'invalid_message' }));
                return;
            }
            bus.emit(sessionId, result.data);
            socket.send(JSON.stringify({ type: 'ack', echo: result.data.type }));
        });
        socket.on('close', () => {
            clearInterval(heartbeat);
            bus.detach(sessionId);
            logger.info({ sessionId }, 'ws closed');
        });
    });
}
//# sourceMappingURL=ws.js.map