"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebServerManager = void 0;
const child_process_1 = require("child_process");
const path_1 = require("path");
const fs_1 = require("fs");
const chalk_1 = __importDefault(require("chalk"));
const express_1 = __importDefault(require("express"));
class WebServerManager {
    static instance;
    webServerProcess = null;
    webServer = null;
    isRunning = false;
    isDevelopment = false;
    constructor() { }
    static getInstance() {
        if (!WebServerManager.instance) {
            WebServerManager.instance = new WebServerManager();
        }
        return WebServerManager.instance;
    }
    async startServer(port = 5173, development = false) {
        if (this.isRunning) {
            throw new Error('Web server is already running');
        }
        this.isDevelopment = development;
        const projectRoot = this.getProjectRoot();
        if (development) {
            // In development, run pnpm dev --filter vite-web-server
            return this.startDevelopmentServer(projectRoot, port);
        }
        else {
            // In production, serve bundled files from CLI's dist/web directory
            return this.startProductionServer(port);
        }
    }
    async startDevelopmentServer(projectRoot, port) {
        const viteAppPath = (0, path_1.join)(projectRoot, 'apps', 'vite-web-server');
        if (!(0, fs_1.existsSync)(viteAppPath)) {
            throw new Error(`Vite web server app not found at: ${viteAppPath}`);
        }
        return new Promise((resolve, reject) => {
            this.webServerProcess = (0, child_process_1.spawn)('pnpm', ['dev', '--filter', 'vite-web-server'], {
                cwd: projectRoot,
                stdio: ['pipe', 'pipe', 'pipe'],
                env: { ...process.env, PORT: port.toString() }
            });
            this.setupProcessHandlers(resolve, reject);
        });
    }
    async startProductionServer(port) {
        const webDistPath = (0, path_1.join)(__dirname, '..', 'web');
        if (!(0, fs_1.existsSync)(webDistPath)) {
            throw new Error(`Web app bundle not found at: ${webDistPath}. Please run 'pnpm build' first.`);
        }
        return new Promise((resolve, reject) => {
            try {
                const app = (0, express_1.default)();
                // Serve static files from the bundled web app
                app.use(express_1.default.static(webDistPath));
                // Handle SPA routing - serve index.html for all routes that don't match static files
                app.get('/*path', (req, res, next) => {
                    // Skip if it's a static file request
                    if (req.path.includes('.')) {
                        return next();
                    }
                    res.sendFile((0, path_1.join)(webDistPath, 'index.html'));
                });
                this.webServer = app.listen(port, () => {
                    this.isRunning = true;
                    resolve();
                });
                this.webServer.on('error', (error) => {
                    if (error.code === 'EADDRINUSE') {
                        reject(new Error(`Port ${port} is already in use`));
                    }
                    else {
                        reject(new Error(`Web server failed to start: ${error.message}`));
                    }
                });
            }
            catch (error) {
                reject(error instanceof Error ? error : new Error('Unknown error starting web server'));
            }
        });
    }
    setupProcessHandlers(resolve, reject) {
        if (!this.webServerProcess) {
            reject(new Error('Web server process not initialized'));
            return;
        }
        let resolved = false;
        this.webServerProcess.stdout?.on('data', (data) => {
            const output = data.toString();
            // Look for server ready indicators
            if ((output.includes('Local:') || output.includes('ready in') || output.includes('Local server')) && !resolved) {
                this.isRunning = true;
                resolved = true;
                resolve();
            }
        });
        this.webServerProcess.stderr?.on('data', (data) => {
            const error = data.toString();
            console.error(chalk_1.default.red(`Web server error: ${error}`));
            // Don't reject on warnings, only on actual errors
            if (error.toLowerCase().includes('error') && !error.toLowerCase().includes('warning') && !resolved) {
                resolved = true;
                reject(new Error(`Web server failed to start: ${error}`));
            }
        });
        this.webServerProcess.on('error', (error) => {
            if (!resolved) {
                resolved = true;
                reject(new Error(`Failed to start web server: ${error.message}`));
            }
        });
        this.webServerProcess.on('exit', (code, signal) => {
            this.isRunning = false;
            this.webServerProcess = null;
            if (code !== 0 && code !== null && !resolved) {
                resolved = true;
                reject(new Error(`Web server exited with code ${code}`));
            }
        });
        // Timeout after 30 seconds
        setTimeout(() => {
            if (!resolved) {
                resolved = true;
                reject(new Error('Web server startup timeout'));
            }
        }, 30000);
    }
    async stopServer() {
        if (!this.isRunning) {
            return;
        }
        return new Promise((resolve) => {
            if (this.isDevelopment && this.webServerProcess) {
                // Stop Vite development server
                this.webServerProcess.on('exit', () => {
                    this.isRunning = false;
                    this.webServerProcess = null;
                    resolve();
                });
                // Try graceful shutdown first
                this.webServerProcess.kill('SIGTERM');
                // Force kill after 5 seconds if still running
                setTimeout(() => {
                    if (this.webServerProcess && !this.webServerProcess.killed) {
                        this.webServerProcess.kill('SIGKILL');
                    }
                }, 5000);
            }
            else if (this.webServer) {
                // Stop Express production server
                this.webServer.close(() => {
                    this.isRunning = false;
                    this.webServer = null;
                    resolve();
                });
            }
            else {
                this.isRunning = false;
                resolve();
            }
        });
    }
    isServerRunning() {
        return this.isRunning;
    }
    getServerUrl(port = 5173) {
        return `http://localhost:${port}`;
    }
    getProjectRoot() {
        // Navigate up from cli-app/src to the monorepo root
        let currentDir = __dirname;
        // Go up until we find package.json with "one-logger" name
        while (currentDir !== '/') {
            const packageJsonPath = (0, path_1.join)(currentDir, 'package.json');
            if ((0, fs_1.existsSync)(packageJsonPath)) {
                try {
                    const packageJson = require(packageJsonPath);
                    if (packageJson.name === 'one-logger') {
                        return currentDir;
                    }
                }
                catch {
                    // Continue searching
                }
            }
            currentDir = (0, path_1.join)(currentDir, '..');
        }
        // Fallback: assume we're in apps/cli-app/src and go up 3 levels
        return (0, path_1.join)(__dirname, '..', '..', '..');
    }
}
exports.WebServerManager = WebServerManager;
//# sourceMappingURL=webServerManager.js.map