import http from 'http';
import { URL } from 'url';
import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
import { getRecentPaths, normalizePathForDisplay } from '../utils/path-resolver.js';
// Import route handlers
import { handleStatusRoutes } from './routes/status-routes.js';
import { handleCliRoutes, cleanupStaleExecutions } from './routes/cli-routes.js';
import { handleCliSettingsRoutes } from './routes/cli-settings-routes.js';
import { handleMemoryRoutes } from './routes/memory-routes.js';
import { handleCoreMemoryRoutes } from './routes/core-memory-routes.js';
import { handleMcpRoutes } from './routes/mcp-routes.js';
import { handleHooksRoutes } from './routes/hooks-routes.js';
import { handleCodexLensRoutes } from './routes/codexlens-routes.js';
import { handleGraphRoutes } from './routes/graph-routes.js';
import { handleSystemRoutes } from './routes/system-routes.js';
import { handleFilesRoutes } from './routes/files-routes.js';
import { handleSkillsRoutes } from './routes/skills-routes.js';
import { handleIssueRoutes } from './routes/issue-routes.js';
import { handleDiscoveryRoutes } from './routes/discovery-routes.js';
import { handleRulesRoutes } from './routes/rules-routes.js';
import { handleSessionRoutes } from './routes/session-routes.js';
import { handleCcwRoutes } from './routes/ccw-routes.js';
import { handleClaudeRoutes } from './routes/claude-routes.js';
import { handleHelpRoutes } from './routes/help-routes.js';
import { handleLiteLLMRoutes } from './routes/litellm-routes.js';
import { handleLiteLLMApiRoutes } from './routes/litellm-api-routes.js';
import { handleNavStatusRoutes } from './routes/nav-status-routes.js';
import { handleAuthRoutes } from './routes/auth-routes.js';
import { handleLoopRoutes } from './routes/loop-routes.js';
import { handleLoopV2Routes, initializeCliToolsCache } from './routes/loop-v2-routes.js';
import { handleTestLoopRoutes } from './routes/test-loop-routes.js';
import { handleTaskRoutes } from './routes/task-routes.js';
// Import WebSocket handling
import { handleWebSocketUpgrade, broadcastToClients, extractSessionIdFromPath } from './websocket.js';
import { getTokenManager } from './auth/token-manager.js';
import { authMiddleware, isLocalhostRequest, setAuthCookie } from './auth/middleware.js';
import { getCorsOrigin } from './cors.js';
import { csrfValidation } from './auth/csrf-middleware.js';
import { getCsrfTokenManager } from './auth/csrf-manager.js';
import { randomBytes } from 'crypto';
// Import health check service
import { getHealthCheckService } from './services/health-check-service.js';
// Import status check functions for warmup
import { checkSemanticStatus, checkVenvStatus } from '../tools/codex-lens.js';
import { getCliToolsStatus } from '../tools/cli-executor.js';
// Template paths
const TEMPLATE_PATH = join(import.meta.dirname, '../../src/templates/dashboard.html');
const MODULE_CSS_DIR = join(import.meta.dirname, '../../src/templates/dashboard-css');
const JS_FILE = join(import.meta.dirname, '../../src/templates/dashboard.js');
const MODULE_JS_DIR = join(import.meta.dirname, '../../src/templates/dashboard-js');
const ASSETS_DIR = join(import.meta.dirname, '../../src/templates/assets');
// Modular CSS files in load order
const MODULE_CSS_FILES = [
    '01-base.css',
    '02-session.css',
    '03-tasks.css',
    '04-lite-tasks.css',
    '05-context.css',
    '06-cards.css',
    '07-managers.css',
    '08-review.css',
    '09-explorer.css',
    // CLI modules (split from 10-cli.css)
    '10-cli-status.css',
    '11-cli-history.css',
    '12-cli-legacy.css',
    '13-cli-ccw.css',
    '14-cli-modals.css',
    '15-cli-endpoints.css',
    '16-cli-session.css',
    '17-cli-conversation.css',
    '18-cli-settings.css',
    '19-cli-native-session.css',
    '20-cli-taskqueue.css',
    '21-cli-toolmgmt.css',
    '22-cli-semantic.css',
    // Other modules
    '23-memory.css',
    '24-prompt-history.css',
    '25-skills-rules.css',
    '26-claude-manager.css',
    '27-graph-explorer.css',
    '28-mcp-manager.css',
    '29-help.css',
    '30-core-memory.css',
    '31-api-settings.css',
    '32-issue-manager.css',
    '33-cli-stream-viewer.css',
    '34-discovery.css',
    '36-loop-monitor.css'
];
// Modular JS files in dependency order
const MODULE_FILES = [
    'i18n.js', // Must be loaded first for translations
    'help-i18n.js', // Help page translations
    'utils.js',
    'state.js',
    'services.js', // CacheManager, EventManager, PreloadService - must be before main.js
    'api.js',
    'components/theme.js',
    'components/modals.js',
    'components/navigation.js',
    'components/sidebar.js',
    'components/tabs-context.js',
    'components/tabs-other.js',
    'components/task-drawer-core.js',
    'components/task-drawer-renderers.js',
    'components/flowchart.js',
    'components/carousel.js',
    'components/notifications.js',
    'components/cli-stream-viewer.js',
    'components/global-notifications.js',
    'components/task-queue-sidebar.js',
    'components/cli-status.js',
    'components/cli-history.js',
    'components/mcp-manager.js',
    'components/hook-manager.js',
    'components/version-check.js',
    'components/storage-manager.js',
    'components/index-manager.js',
    'components/_exp_helpers.js',
    'components/_conflict_tab.js',
    'components/_review_tab.js',
    'views/home.js',
    'views/project-overview.js',
    'views/session-detail.js',
    'views/review-session.js',
    'views/lite-tasks.js',
    'views/fix-session.js',
    'views/cli-manager.js',
    'views/codexlens-manager.js',
    'views/explorer.js',
    'views/mcp-manager.js',
    'views/hook-manager.js',
    'views/history.js',
    'views/graph-explorer.js',
    'views/memory.js',
    'views/core-memory.js',
    'views/core-memory-graph.js',
    'views/core-memory-clusters.js',
    'views/prompt-history.js',
    'views/skills-manager.js',
    'views/rules-manager.js',
    'views/claude-manager.js',
    'views/api-settings.js',
    'views/help.js',
    'views/issue-manager.js',
    'views/issue-discovery.js',
    'views/loop-monitor.js',
    'main.js'
];
/**
 * Handle POST request with JSON body
 */
function handlePostRequest(req, res, handler) {
    const cachedParsed = req.body;
    const cachedRawBody = req.__ccwRawBody;
    const handleBody = async (parsed) => {
        try {
            const result = await handler(parsed);
            const isObjectResult = typeof result === 'object' && result !== null;
            const errorValue = isObjectResult && 'error' in result ? result.error : undefined;
            const statusValue = isObjectResult && 'status' in result ? result.status : undefined;
            if (typeof errorValue === 'string' && errorValue.length > 0) {
                const status = typeof statusValue === 'number' ? statusValue : 500;
                res.writeHead(status, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: errorValue }));
                return;
            }
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(result));
        }
        catch (error) {
            const message = error instanceof Error ? error.message : String(error);
            res.writeHead(500, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: message }));
        }
    };
    if (cachedParsed !== undefined) {
        void handleBody(cachedParsed);
        return;
    }
    if (typeof cachedRawBody === 'string') {
        try {
            void handleBody(JSON.parse(cachedRawBody));
        }
        catch (error) {
            const message = error instanceof Error ? error.message : String(error);
            res.writeHead(500, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: message }));
        }
        return;
    }
    let body = '';
    req.on('data', (chunk) => { body += chunk.toString(); });
    req.on('end', async () => {
        try {
            req.__ccwRawBody = body;
            const parsed = JSON.parse(body);
            req.body = parsed;
            await handleBody(parsed);
        }
        catch (error) {
            const message = error instanceof Error ? error.message : String(error);
            res.writeHead(500, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: message }));
        }
    });
}
function getHeaderValue(header) {
    if (!header)
        return null;
    if (Array.isArray(header))
        return header[0] ?? null;
    return header;
}
function parseCookieHeader(cookieHeader) {
    if (!cookieHeader)
        return {};
    const cookies = {};
    for (const part of cookieHeader.split(';')) {
        const [rawName, ...rawValueParts] = part.trim().split('=');
        if (!rawName)
            continue;
        const rawValue = rawValueParts.join('=');
        try {
            cookies[rawName] = decodeURIComponent(rawValue);
        }
        catch {
            cookies[rawName] = rawValue;
        }
    }
    return cookies;
}
function appendSetCookie(res, cookie) {
    const existing = res.getHeader('Set-Cookie');
    if (!existing) {
        res.setHeader('Set-Cookie', cookie);
        return;
    }
    if (Array.isArray(existing)) {
        res.setHeader('Set-Cookie', [...existing, cookie]);
        return;
    }
    res.setHeader('Set-Cookie', [String(existing), cookie]);
}
function getOrCreateSessionId(req, res) {
    const cookies = parseCookieHeader(getHeaderValue(req.headers.cookie));
    const existing = cookies.ccw_session_id;
    if (existing)
        return existing;
    const created = randomBytes(16).toString('hex');
    const attributes = [
        `ccw_session_id=${encodeURIComponent(created)}`,
        'Path=/',
        'HttpOnly',
        'SameSite=Strict',
        `Max-Age=${24 * 60 * 60}`,
    ];
    appendSetCookie(res, attributes.join('; '));
    return created;
}
function setCsrfCookie(res, token, maxAgeSeconds) {
    const attributes = [
        `XSRF-TOKEN=${encodeURIComponent(token)}`,
        'Path=/',
        'HttpOnly',
        'SameSite=Strict',
        `Max-Age=${maxAgeSeconds}`,
    ];
    appendSetCookie(res, attributes.join('; '));
}
/**
 * Warmup function to pre-populate caches on server startup
 * This runs asynchronously and non-blocking after the server starts
 */
async function warmupCaches(initialPath) {
    console.log('[WARMUP] Starting cache warmup...');
    const startTime = Date.now();
    // Run all warmup tasks in parallel for faster startup
    const warmupTasks = [
        // Warmup semantic status cache (Python process startup - can be slow first time)
        (async () => {
            const taskStart = Date.now();
            try {
                const semanticStatus = await checkSemanticStatus();
                console.log(`[WARMUP] Semantic status: ${semanticStatus.available ? 'available' : 'not available'} (${Date.now() - taskStart}ms)`);
            }
            catch (err) {
                console.warn(`[WARMUP] Semantic status check failed: ${err.message}`);
            }
        })(),
        // Warmup venv status cache
        (async () => {
            const taskStart = Date.now();
            try {
                const venvStatus = await checkVenvStatus();
                console.log(`[WARMUP] Venv status: ${venvStatus.ready ? 'ready' : 'not ready'} (${Date.now() - taskStart}ms)`);
            }
            catch (err) {
                console.warn(`[WARMUP] Venv status check failed: ${err.message}`);
            }
        })(),
        // Warmup CLI tools status cache
        (async () => {
            const taskStart = Date.now();
            try {
                const cliStatus = await getCliToolsStatus();
                const availableCount = Object.values(cliStatus).filter(s => s.available).length;
                const totalCount = Object.keys(cliStatus).length;
                console.log(`[WARMUP] CLI tools status: ${availableCount}/${totalCount} available (${Date.now() - taskStart}ms)`);
            }
            catch (err) {
                console.warn(`[WARMUP] CLI tools status check failed: ${err.message}`);
            }
        })()
    ];
    await Promise.allSettled(warmupTasks);
    console.log(`[WARMUP] Cache warmup complete (${Date.now() - startTime}ms total)`);
}
/**
 * Generate dashboard HTML with embedded CSS and JS
 */
function generateServerDashboard(initialPath) {
    let html = readFileSync(TEMPLATE_PATH, 'utf8');
    // Read and concatenate modular CSS files in load order
    const cssContent = MODULE_CSS_FILES.map(file => {
        const filePath = join(MODULE_CSS_DIR, file);
        return existsSync(filePath) ? readFileSync(filePath, 'utf8') : '';
    }).join('\n\n');
    // Read and concatenate modular JS files in dependency order
    let jsContent = MODULE_FILES.map(file => {
        const filePath = join(MODULE_JS_DIR, file);
        if (!existsSync(filePath)) {
            console.error(`[Dashboard] Critical module file not found: ${filePath}`);
            console.error(`[Dashboard] Expected path relative to: ${MODULE_JS_DIR}`);
            console.error(`[Dashboard] Check that the file exists and is included in the build.`);
            // Return empty string with error comment to make the issue visible in browser
            return `console.error('[Dashboard] Module not loaded: ${file} (see server console for details)');\n`;
        }
        return readFileSync(filePath, 'utf8');
    }).join('\n\n');
    // Inject CSS content
    html = html.replace('{{CSS_CONTENT}}', cssContent);
    // Prepare JS content with empty initial data (will be loaded dynamically)
    const emptyData = {
        generatedAt: new Date().toISOString(),
        activeSessions: [],
        archivedSessions: [],
        liteTasks: { litePlan: [], liteFix: [], multiCliPlan: [] },
        reviewData: { dimensions: {} },
        projectOverview: null,
        statistics: { totalSessions: 0, activeSessions: 0, totalTasks: 0, completedTasks: 0, reviewFindings: 0, litePlanCount: 0, liteFixCount: 0, multiCliPlanCount: 0 }
    };
    // Replace JS placeholders
    jsContent = jsContent.replace('{{WORKFLOW_DATA}}', JSON.stringify(emptyData, null, 2));
    jsContent = jsContent.replace(/\{\{PROJECT_PATH\}\}/g, normalizePathForDisplay(initialPath).replace(/\\/g, '/'));
    jsContent = jsContent.replace('{{RECENT_PATHS}}', JSON.stringify(getRecentPaths()));
    // Add server mode flag at the start of JS
    const serverModeScript = `
// Server mode - load data dynamically
window.SERVER_MODE = true;
window.INITIAL_PATH = '${normalizePathForDisplay(initialPath).replace(/\\/g, '/')}';
`;
    // Prepend server mode script to JS content
    jsContent = serverModeScript + jsContent;
    // Inject JS content
    html = html.replace('{{JS_CONTENT}}', jsContent);
    // Replace any remaining placeholders in HTML
    html = html.replace(/\{\{PROJECT_PATH\}\}/g, normalizePathForDisplay(initialPath).replace(/\\/g, '/'));
    return html;
}
/**
 * Create and start the dashboard server
 * @param {Object} options - Server options
 * @param {number} options.port - Port to listen on (default: 3456)
 * @param {string} options.initialPath - Initial project path
 * @returns {Promise<http.Server>}
 */
export async function startServer(options = {}) {
    let serverPort = options.port ?? 3456;
    const initialPath = options.initialPath || process.cwd();
    const host = options.host ?? '127.0.0.1';
    const tokenManager = getTokenManager();
    const secretKey = tokenManager.getSecretKey();
    tokenManager.getOrCreateAuthToken();
    const unauthenticatedPaths = new Set(['/api/auth/token', '/api/csrf-token', '/api/hook']);
    const server = http.createServer(async (req, res) => {
        const url = new URL(req.url ?? '/', `http://localhost:${serverPort}`);
        const pathname = url.pathname;
        // CORS headers for API requests
        const originHeader = Array.isArray(req.headers.origin) ? req.headers.origin[0] : req.headers.origin;
        res.setHeader('Access-Control-Allow-Origin', getCorsOrigin(originHeader, serverPort));
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
        res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-CSRF-Token');
        res.setHeader('Access-Control-Allow-Credentials', 'true');
        res.setHeader('Access-Control-Expose-Headers', 'X-CSRF-Token');
        res.setHeader('Vary', 'Origin');
        if (req.method === 'OPTIONS') {
            res.writeHead(200);
            res.end();
            return;
        }
        try {
            // Debug log for API requests
            if (pathname.startsWith('/api/')) {
                console.log(`[API] ${req.method} ${pathname}`);
            }
            // Route context for all handlers
            const routeContext = {
                pathname,
                url,
                req,
                res,
                initialPath,
                handlePostRequest,
                broadcastToClients,
                extractSessionIdFromPath,
                server
            };
            // Token acquisition endpoint (localhost-only)
            if (pathname === '/api/auth/token') {
                if (!isLocalhostRequest(req)) {
                    res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' });
                    res.end(JSON.stringify({ error: 'Forbidden' }));
                    return;
                }
                const tokenResult = tokenManager.getOrCreateAuthToken();
                setAuthCookie(res, tokenResult.token, tokenResult.expiresAt);
                res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
                res.end(JSON.stringify({ token: tokenResult.token, expiresAt: tokenResult.expiresAt.toISOString() }));
                return;
            }
            // Authentication middleware for all API routes
            if (pathname.startsWith('/api/')) {
                const ok = authMiddleware({ pathname, req, res, tokenManager, secretKey, unauthenticatedPaths });
                if (!ok)
                    return;
            }
            // CSRF validation middleware for state-changing API routes
            if (pathname.startsWith('/api/')) {
                const ok = await csrfValidation({ pathname, req, res });
                if (!ok)
                    return;
            }
            // Try each route handler in order
            // Order matters: more specific routes should come before general ones
            // Auth routes (/api/csrf-token)
            if (await handleAuthRoutes(routeContext))
                return;
            // Status routes (/api/status/*) - Aggregated endpoint for faster loading
            if (pathname.startsWith('/api/status/')) {
                if (await handleStatusRoutes(routeContext))
                    return;
            }
            // Navigation status routes (/api/nav-status) - Aggregated badge counts
            if (pathname === '/api/nav-status') {
                if (await handleNavStatusRoutes(routeContext))
                    return;
            }
            // CLI routes (/api/cli/*)
            if (pathname.startsWith('/api/cli/')) {
                // CLI Settings routes first (more specific path /api/cli/settings/*)
                if (await handleCliSettingsRoutes(routeContext))
                    return;
                if (await handleCliRoutes(routeContext))
                    return;
            }
            // Claude CLAUDE.md routes (/api/memory/claude/*) and Language routes (/api/language/*)
            if (pathname.startsWith('/api/memory/claude/') || pathname.startsWith('/api/language/')) {
                if (await handleClaudeRoutes(routeContext))
                    return;
            }
            // Memory routes (/api/memory/*)
            if (pathname.startsWith('/api/memory/')) {
                if (await handleMemoryRoutes(routeContext))
                    return;
            }
            // Core Memory routes (/api/core-memory/*)
            if (pathname.startsWith('/api/core-memory/')) {
                if (await handleCoreMemoryRoutes(routeContext))
                    return;
            }
            // MCP routes (/api/mcp*, /api/codex-mcp*)
            if (pathname.startsWith('/api/mcp') || pathname.startsWith('/api/codex-mcp')) {
                if (await handleMcpRoutes(routeContext))
                    return;
            }
            // Hooks routes (/api/hooks, /api/hook)
            if (pathname.startsWith('/api/hook')) {
                if (await handleHooksRoutes(routeContext))
                    return;
            }
            // CodexLens routes (/api/codexlens/*)
            if (pathname.startsWith('/api/codexlens/')) {
                if (await handleCodexLensRoutes(routeContext))
                    return;
            }
            // LiteLLM routes (/api/litellm/*)
            if (pathname.startsWith('/api/litellm/')) {
                if (await handleLiteLLMRoutes(routeContext))
                    return;
            }
            // LiteLLM API routes (/api/litellm-api/*)
            if (pathname.startsWith('/api/litellm-api/')) {
                if (await handleLiteLLMApiRoutes(routeContext))
                    return;
            }
            // Graph routes (/api/graph/*)
            if (pathname.startsWith('/api/graph/')) {
                if (await handleGraphRoutes(routeContext))
                    return;
            }
            // CCW routes (/api/ccw/*)
            if (pathname.startsWith('/api/ccw/')) {
                if (await handleCcwRoutes(routeContext))
                    return;
            }
            // Loop V2 routes (/api/loops/v2/*) - must be checked before v1
            if (pathname.startsWith('/api/loops/v2')) {
                if (await handleLoopV2Routes(routeContext))
                    return;
            }
            // Loop V1 routes (/api/loops/*) - backward compatibility
            if (pathname.startsWith('/api/loops')) {
                if (await handleLoopRoutes(routeContext))
                    return;
            }
            // Task routes (/api/tasks)
            if (pathname.startsWith('/api/tasks')) {
                if (await handleTaskRoutes(routeContext))
                    return;
            }
            // Test loop routes (/api/test/loop*)
            if (pathname.startsWith('/api/test/loop')) {
                if (await handleTestLoopRoutes(routeContext))
                    return;
            }
            // Skills routes (/api/skills*)
            if (pathname.startsWith('/api/skills')) {
                if (await handleSkillsRoutes(routeContext))
                    return;
            }
            // Queue routes (/api/queue*) - top-level queue API
            if (pathname.startsWith('/api/queue')) {
                if (await handleIssueRoutes(routeContext))
                    return;
            }
            // Issue routes (/api/issues*)
            if (pathname.startsWith('/api/issues')) {
                if (await handleIssueRoutes(routeContext))
                    return;
            }
            // Discovery routes (/api/discoveries*)
            if (pathname.startsWith('/api/discoveries')) {
                if (await handleDiscoveryRoutes(routeContext))
                    return;
            }
            // Rules routes (/api/rules*)
            if (pathname.startsWith('/api/rules')) {
                if (await handleRulesRoutes(routeContext))
                    return;
            }
            // Help routes (/api/help/*)
            if (pathname.startsWith('/api/help/')) {
                if (await handleHelpRoutes(routeContext))
                    return;
            }
            // Session routes (/api/session-detail, /api/update-task-status, /api/bulk-update-task-status)
            if (pathname.includes('session') || pathname.includes('task-status')) {
                if (await handleSessionRoutes(routeContext))
                    return;
            }
            // Files routes (/api/files, /api/file, /api/file-content, /api/update-claude-md)
            if (pathname === '/api/files' || pathname === '/api/file' ||
                pathname === '/api/file-content' || pathname === '/api/update-claude-md') {
                if (await handleFilesRoutes(routeContext))
                    return;
            }
            // System routes (data, health, version, paths, shutdown, notify, storage, dialog)
            if (pathname === '/api/data' || pathname === '/api/health' ||
                pathname === '/api/version-check' || pathname === '/api/shutdown' ||
                pathname === '/api/recent-paths' || pathname === '/api/switch-path' ||
                pathname === '/api/remove-recent-path' || pathname === '/api/system/notify' ||
                pathname.startsWith('/api/storage/') || pathname.startsWith('/api/dialog/')) {
                if (await handleSystemRoutes(routeContext))
                    return;
            }
            // Serve dashboard HTML
            if (pathname === '/' || pathname === '/index.html') {
                // Set session cookie and CSRF token for all requests
                const tokenResult = tokenManager.getOrCreateAuthToken();
                setAuthCookie(res, tokenResult.token, tokenResult.expiresAt);
                const sessionId = getOrCreateSessionId(req, res);
                const csrfToken = getCsrfTokenManager().generateToken(sessionId);
                res.setHeader('X-CSRF-Token', csrfToken);
                setCsrfCookie(res, csrfToken, 15 * 60);
                const html = generateServerDashboard(initialPath);
                res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
                res.end(html);
                return;
            }
            // Handle favicon.ico (return empty response to prevent 404)
            if (pathname === '/favicon.ico') {
                res.writeHead(204);
                res.end();
                return;
            }
            // Serve static assets (js, css, images, fonts)
            if (pathname.startsWith('/assets/')) {
                const assetPath = join(ASSETS_DIR, pathname.replace('/assets/', ''));
                if (existsSync(assetPath)) {
                    const ext = assetPath.split('.').pop()?.toLowerCase();
                    const mimeTypes = {
                        'js': 'application/javascript',
                        'css': 'text/css',
                        'json': 'application/json',
                        'png': 'image/png',
                        'jpg': 'image/jpeg',
                        'jpeg': 'image/jpeg',
                        'svg': 'image/svg+xml',
                        'woff': 'font/woff',
                        'woff2': 'font/woff2',
                        'ttf': 'font/ttf'
                    };
                    const contentType = ext ? mimeTypes[ext] ?? 'application/octet-stream' : 'application/octet-stream';
                    const content = readFileSync(assetPath);
                    res.writeHead(200, {
                        'Content-Type': contentType,
                        'Cache-Control': 'no-cache, must-revalidate'
                    });
                    res.end(content);
                    return;
                }
            }
            // 404
            res.writeHead(404, { 'Content-Type': 'text/plain' });
            res.end('Not Found');
        }
        catch (error) {
            console.error('Server error:', error);
            const message = error instanceof Error ? error.message : String(error);
            res.writeHead(500, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ error: message }));
        }
    });
    // Handle WebSocket upgrade requests
    server.on('upgrade', (req, socket, head) => {
        if (req.url === '/ws') {
            handleWebSocketUpgrade(req, socket, head);
        }
        else {
            socket.destroy();
        }
    });
    return new Promise((resolve, reject) => {
        server.listen(serverPort, host, () => {
            const addr = server.address();
            if (addr && typeof addr === 'object') {
                serverPort = addr.port;
            }
            console.log(`Dashboard server running at http://${host}:${serverPort}`);
            console.log(`WebSocket endpoint available at ws://${host}:${serverPort}/ws`);
            console.log(`Hook endpoint available at POST http://${host}:${serverPort}/api/hook`);
            // Initialize CLI tools cache for Loop V2 routes
            initializeCliToolsCache();
            // Start periodic cleanup of stale CLI executions (every 2 minutes)
            const CLEANUP_INTERVAL_MS = 2 * 60 * 1000;
            const cleanupInterval = setInterval(cleanupStaleExecutions, CLEANUP_INTERVAL_MS);
            server.on('close', () => {
                clearInterval(cleanupInterval);
                console.log('[Server] Stopped CLI execution cleanup interval');
            });
            // Start health check service for all enabled providers
            try {
                const healthCheckService = getHealthCheckService();
                healthCheckService.startAllHealthChecks(initialPath);
                // Graceful shutdown: stop health checks when server closes
                server.on('close', () => {
                    console.log('[Server] Shutting down health check service...');
                    healthCheckService.stopAllHealthChecks();
                });
            }
            catch (err) {
                console.warn('[Server] Failed to start health check service:', err);
            }
            // Start cache warmup asynchronously (non-blocking)
            // Uses setImmediate to not delay server startup response
            setImmediate(() => {
                warmupCaches(initialPath).catch((err) => {
                    console.warn('[WARMUP] Cache warmup failed:', err);
                });
            });
            resolve(server);
        });
        server.on('error', reject);
    });
}
//# sourceMappingURL=server.js.map