/**
 * Server Startup
 *
 * Cross-runtime server initialization for Bun and Node.js.
 */
import { PORT as DEFAULT_PORT, HOST as DEFAULT_HOST } from './config.js';
import { handleWSOpen, handleWSMessage, handleWSClose } from './websocket.js';
import { handleLspWSOpen, handleLspWSMessage, handleLspWSClose } from './lsp-websocket.js';
import { handleEventsWSOpen, handleEventsWSMessage, handleEventsWSClose } from './events-websocket.js';
const isBun = typeof globalThis.Bun !== 'undefined';
export function startServer(app, services, lspManager, options) {
    if (isBun) {
        startBunServer(app, services, lspManager, options);
    }
    else {
        startNodeServer(app, services, lspManager, options);
    }
}
function startBunServer(app, services, lspManager, options) {
    const PORT = options?.port ?? DEFAULT_PORT;
    const HOST = options?.host ?? DEFAULT_HOST;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const Bun = globalThis.Bun;
    const server = Bun.serve({
        port: PORT,
        hostname: HOST,
        fetch: app.fetch,
        websocket: {
            open(ws) {
                const data = ws.data;
                if (data.wsType === 'events') {
                    handleEventsWSOpen(ws);
                }
                else if (data.wsType === 'lsp') {
                    // LSP open is handled after upgrade with language param
                }
                else {
                    handleWSOpen(ws);
                }
            },
            message(ws, message) {
                const data = ws.data;
                if (data.wsType === 'events') {
                    handleEventsWSMessage(ws, message);
                }
                else if (data.wsType === 'lsp') {
                    handleLspWSMessage(ws, message);
                }
                else {
                    handleWSMessage(ws, message, services);
                }
            },
            close(ws) {
                const data = ws.data;
                if (data.wsType === 'events') {
                    handleEventsWSClose(ws);
                }
                else if (data.wsType === 'lsp') {
                    handleLspWSClose(ws);
                }
                else {
                    handleWSClose(ws);
                }
            },
        },
    });
    // Terminal WebSocket endpoint
    app.get('/ws', (c) => {
        const upgraded = server.upgrade(c.req.raw, { data: { id: '', wsType: 'terminal' } });
        return upgraded ? new Response(null, { status: 101 }) : c.json({ error: 'WebSocket upgrade failed' }, 400);
    });
    // Event-subscription WebSocket endpoint
    app.get('/ws/events', (c) => {
        const upgraded = server.upgrade(c.req.raw, { data: { id: '', wsType: 'events' } });
        return upgraded ? new Response(null, { status: 101 }) : c.json({ error: 'WebSocket upgrade failed' }, 400);
    });
    // LSP WebSocket endpoint
    app.get('/ws/lsp', (c) => {
        const language = c.req.query('language');
        if (!language) {
            return c.json({ error: 'Language query parameter is required' }, 400);
        }
        if (!lspManager) {
            return c.json({ error: 'LSP manager not available' }, 503);
        }
        const upgraded = server.upgrade(c.req.raw, { data: { id: '', language, wsType: 'lsp', isLsp: true } });
        return upgraded ? new Response(null, { status: 101 }) : c.json({ error: 'WebSocket upgrade failed' }, 400);
    });
    console.log(`[orchestrator] Server running at http://${HOST}:${PORT} (Bun)`);
    console.log(`[orchestrator] WebSocket available at ws://${HOST}:${PORT}/ws`);
    console.log(`[orchestrator] Events WebSocket available at ws://${HOST}:${PORT}/ws/events`);
    if (lspManager) {
        console.log(`[orchestrator] LSP WebSocket available at ws://${HOST}:${PORT}/ws/lsp?language=<lang>`);
    }
}
function startNodeServer(app, services, lspManager, options) {
    const PORT = options?.port ?? DEFAULT_PORT;
    const HOST = options?.host ?? DEFAULT_HOST;
    import('ws').then(({ WebSocketServer }) => {
        import('http').then(({ createServer }) => {
            import('url').then(({ parse: parseUrl }) => {
                const httpServer = createServer(async (req, res) => {
                    const url = `http://${HOST}:${PORT}${req.url}`;
                    const headers = new Headers();
                    for (const [key, value] of Object.entries(req.headers)) {
                        if (value)
                            headers.set(key, Array.isArray(value) ? value.join(', ') : value);
                    }
                    let body;
                    if (req.method !== 'GET' && req.method !== 'HEAD') {
                        const chunks = [];
                        for await (const chunk of req) {
                            chunks.push(chunk);
                        }
                        body = Buffer.concat(chunks).toString();
                    }
                    const request = new Request(url, { method: req.method, headers, body });
                    const response = await app.fetch(request);
                    res.statusCode = response.status;
                    response.headers.forEach((value, key) => res.setHeader(key, value));
                    if (response.body) {
                        const reader = response.body.getReader();
                        const pump = async () => {
                            try {
                                const { done, value } = await reader.read();
                                if (done) {
                                    res.end();
                                    return;
                                }
                                res.write(value);
                                return pump();
                            }
                            catch {
                                res.end();
                            }
                        };
                        await pump();
                    }
                    else {
                        res.end(await response.text());
                    }
                });
                // Main WebSocket server for agent terminal connections
                const wss = new WebSocketServer({ noServer: true });
                wss.on('connection', (ws) => {
                    const wsData = {
                        id: `ws-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
                    };
                    const WS_OPEN = 1;
                    const wsAdapter = {
                        data: wsData,
                        send: (data) => {
                            if (ws.readyState === WS_OPEN) {
                                ws.send(typeof data === 'string' ? data : Buffer.from(data));
                            }
                        },
                        close: () => ws.close(),
                        readyState: ws.readyState,
                    };
                    handleWSOpen(wsAdapter);
                    ws.on('message', (msg) => {
                        wsAdapter.readyState = ws.readyState;
                        handleWSMessage(wsAdapter, msg.toString(), services);
                    });
                    ws.on('close', () => handleWSClose(wsAdapter));
                });
                // Event-subscription WebSocket server
                const eventsWss = new WebSocketServer({ noServer: true });
                eventsWss.on('connection', (ws) => {
                    const WS_OPEN = 1;
                    const wsAdapter = {
                        data: {
                            id: '',
                            wsType: 'events',
                            subscriptions: new Set(),
                            eventListener: () => { },
                        },
                        send: (data) => {
                            if (ws.readyState === WS_OPEN) {
                                ws.send(typeof data === 'string' ? data : Buffer.from(data));
                            }
                        },
                        close: () => ws.close(),
                        readyState: ws.readyState,
                    };
                    handleEventsWSOpen(wsAdapter);
                    ws.on('message', (msg) => {
                        wsAdapter.readyState = ws.readyState;
                        handleEventsWSMessage(wsAdapter, msg.toString());
                    });
                    ws.on('close', () => handleEventsWSClose(wsAdapter));
                });
                // LSP WebSocket server for language server connections
                const lspWss = new WebSocketServer({ noServer: true });
                lspWss.on('connection', (ws, req) => {
                    const parsedUrl = parseUrl(req.url || '', true);
                    const language = parsedUrl.query.language;
                    if (!language) {
                        ws.close(1002, 'Language query parameter is required');
                        return;
                    }
                    if (!lspManager) {
                        ws.close(1002, 'LSP manager not available');
                        return;
                    }
                    const WS_OPEN = 1;
                    const wsAdapter = {
                        data: { id: '', language },
                        send: (data) => {
                            if (ws.readyState === WS_OPEN) {
                                ws.send(typeof data === 'string' ? data : Buffer.from(data));
                            }
                        },
                        close: () => ws.close(),
                        readyState: ws.readyState,
                    };
                    handleLspWSOpen(wsAdapter, language, lspManager);
                    ws.on('message', (msg) => {
                        wsAdapter.readyState = ws.readyState;
                        handleLspWSMessage(wsAdapter, msg.toString());
                    });
                    ws.on('close', () => handleLspWSClose(wsAdapter));
                });
                // Handle upgrade requests to route to appropriate WebSocket server
                httpServer.on('upgrade', (req, socket, head) => {
                    const pathname = parseUrl(req.url || '').pathname;
                    if (pathname === '/ws/events') {
                        eventsWss.handleUpgrade(req, socket, head, (ws) => {
                            eventsWss.emit('connection', ws, req);
                        });
                    }
                    else if (pathname === '/ws/lsp') {
                        lspWss.handleUpgrade(req, socket, head, (ws) => {
                            lspWss.emit('connection', ws, req);
                        });
                    }
                    else if (pathname === '/ws') {
                        wss.handleUpgrade(req, socket, head, (ws) => {
                            wss.emit('connection', ws, req);
                        });
                    }
                    else {
                        socket.destroy();
                    }
                });
                httpServer.listen(PORT, HOST, () => {
                    console.log(`[orchestrator] Server running at http://${HOST}:${PORT} (Node.js)`);
                    console.log(`[orchestrator] WebSocket available at ws://${HOST}:${PORT}/ws`);
                    console.log(`[orchestrator] Events WebSocket available at ws://${HOST}:${PORT}/ws/events`);
                    if (lspManager) {
                        console.log(`[orchestrator] LSP WebSocket available at ws://${HOST}:${PORT}/ws/lsp?language=<lang>`);
                    }
                });
            });
        });
    });
}
//# sourceMappingURL=server.js.map