#!/usr/bin/env node
"use strict";
/**
 * WebUI subcommand for dominds CLI
 *
 * Usage:
 *   dominds webui [options]
 *
 * Options:
 *   -p, --port <port>    Port to listen on. Bare port is strict; suffix + tries higher ports; suffix - tries lower ports.
 *   -h, --host <host>    Host to bind to (default: localhost)
 *   --nobrowser          Do not open a browser (opt-out)
 *   --help               Show help
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.main = main;
const child_process_1 = require("child_process");
const log_1 = require("../log");
const process_title_1 = require("../process-title");
const work_language_1 = require("../runtime/work-language");
const server_1 = require("../server");
const auth_1 = require("../server/auth");
const port_selection_1 = require("../server/port-selection");
const log = (0, log_1.createLogger)('webui');
function formatWebSocketEndpoint(params) {
    const httpOrigin = (0, auth_1.formatServerOrigin)({
        scheme: params.scheme === 'ws' ? 'http' : 'https',
        host: params.host,
        port: params.port,
    });
    return `${params.scheme}${httpOrigin.slice(httpOrigin.indexOf(':'))}/ws`;
}
function printHelp() {
    console.log(`
WebUI Server for dominds

Usage:
  dominds webui [options]

Note:
  rtws (runtime workspace) directory is \`process.cwd()\`. Use 'dominds -C <dir> webui' to run in another rtws.

Options:
  -p, --port <port>    Port to listen on. Bare port is strict; suffix + tries higher ports; suffix - tries lower ports.
                       Default without --port: auto from 5666 downward.
  -h, --host <host>    Host to bind to (default: localhost)
  --mode <dev|prod>    Server mode (default: prod; dev if NODE_ENV=dev)
  --nobrowser          Do not open a browser (opt-out)
  --help               Show this help message

Examples:
  dominds webui                   # Start on 5666, or the next available lower port
  dominds webui -p 8888           # Start strictly on port 8888
  dominds webui -p 8888+          # Start on 8888, or the next available higher port
  dominds webui -p 8888-          # Start on 8888, or the next available lower port
  dominds webui --mode dev        # Start in dev mode
  dominds webui --nobrowser       # Start without opening a browser
`);
}
function openInBrowser(url) {
    // Best-effort cross-platform open.
    // We intentionally do not await; failures should not crash the server.
    const platform = process.platform;
    if (platform === 'darwin') {
        (0, child_process_1.spawn)('open', [url], { stdio: 'ignore', detached: true }).unref();
        return;
    }
    if (platform === 'win32') {
        (0, child_process_1.spawn)('cmd', ['/c', 'start', '', url], { stdio: 'ignore', detached: true }).unref();
        return;
    }
    (0, child_process_1.spawn)('xdg-open', [url], { stdio: 'ignore', detached: true }).unref();
}
async function main(args = process.argv.slice(2)) {
    (0, process_title_1.setRtwsProcessTitle)();
    let port;
    let host = 'localhost';
    let mode = process.env.NODE_ENV === 'dev' ? 'dev' : 'prod';
    let shouldOpen = true;
    let strictPort = false;
    let portAutoDirection = 'down';
    for (let i = 0; i < args.length; i++) {
        const arg = args[i];
        if (arg === '-p' || arg === '--port') {
            const next = args[i + 1];
            const parsedPort = next ? (0, port_selection_1.parseWebuiPortSpec)(next) : null;
            if (parsedPort === null) {
                console.error('Error: --port requires a valid port number, optionally suffixed with + or -');
                printHelp();
                process.exit(1);
            }
            port = parsedPort.port;
            strictPort = parsedPort.strictPort;
            portAutoDirection = parsedPort.portAutoDirection;
            i++;
        }
        else if (arg.startsWith('--port=')) {
            const parsedPort = (0, port_selection_1.parseWebuiPortSpec)(arg.slice('--port='.length));
            if (parsedPort === null) {
                console.error('Error: --port requires a valid port number, optionally suffixed with + or -');
                printHelp();
                process.exit(1);
            }
            port = parsedPort.port;
            strictPort = parsedPort.strictPort;
            portAutoDirection = parsedPort.portAutoDirection;
        }
        else if (arg === '-h' || arg === '--host') {
            const next = args[i + 1];
            if (!next) {
                console.error('Error: --host requires a hostname');
                printHelp();
                process.exit(1);
            }
            host = next;
            i++;
        }
        else if (arg === '--mode') {
            const next = args[i + 1];
            if (next !== 'dev' && next !== 'prod') {
                console.error(`Error: --mode must be 'dev' or 'prod'`);
                printHelp();
                process.exit(1);
            }
            mode = next;
            i++;
        }
        else if (arg === '--nobrowser') {
            shouldOpen = false;
        }
        else if (arg === '--help') {
            printHelp();
            process.exit(0);
        }
        else {
            console.error(`Error: Unknown option '${arg}'`);
            printHelp();
            process.exit(1);
        }
    }
    log.info('Starting Dominds WebUI…');
    try {
        const { language: resolvedLanguage, source } = (0, work_language_1.resolveWorkLanguage)({ env: process.env });
        (0, work_language_1.setWorkLanguage)(resolvedLanguage);
        log.info(`working language: ${(0, work_language_1.getWorkLanguage)()} (source: ${source})`);
        const started = await (0, server_1.startServer)({
            port,
            host,
            mode,
            strictPort,
            portAutoDirection,
            returnAfterListen: true,
        });
        const httpServer = started.httpServer;
        const auth = started.auth;
        const baseUrl = (0, auth_1.formatServerOrigin)({
            scheme: 'http',
            host: started.urlHost,
            port: started.port,
        });
        log.info(`WebUI ready: ${baseUrl}`);
        log.debug(`WebSocket endpoint: ${formatWebSocketEndpoint({
            scheme: 'ws',
            host: started.urlHost,
            port: started.port,
        })}`);
        let httpsEndpoint;
        if (started.httpsPort !== undefined && started.httpsUrlHost !== undefined) {
            httpsEndpoint = { host: started.httpsUrlHost, port: started.httpsPort };
            const httpsBaseUrl = (0, auth_1.formatServerOrigin)({
                scheme: 'https',
                host: httpsEndpoint.host,
                port: httpsEndpoint.port,
            });
            log.info(`HTTPS WebUI ready: ${httpsBaseUrl}`);
            log.debug(`HTTPS WebSocket endpoint: ${formatWebSocketEndpoint({
                scheme: 'wss',
                host: httpsEndpoint.host,
                port: httpsEndpoint.port,
            })}`);
        }
        if (auth.kind === 'enabled') {
            const autoAuthUrl = (0, auth_1.formatAutoAuthUrl)({
                scheme: 'http',
                host: started.urlHost,
                port: started.port,
                authKey: auth.key,
            });
            log.info(`auto auth url (sensitive): ${autoAuthUrl}`);
            if (httpsEndpoint !== undefined) {
                log.info(`HTTPS auto auth url (sensitive): ${(0, auth_1.formatAutoAuthUrl)({
                    scheme: 'https',
                    host: httpsEndpoint.host,
                    port: httpsEndpoint.port,
                    authKey: auth.key,
                })}`);
            }
            if (shouldOpen) {
                log.debug(`Opening browser: ${autoAuthUrl}`);
                openInBrowser(autoAuthUrl);
            }
        }
        else {
            log.info('auth: disabled');
            if (shouldOpen) {
                const url = `${baseUrl}/`;
                log.debug(`Opening browser: ${url}`);
                openInBrowser(url);
            }
        }
        // Handle graceful shutdown
        process.on('SIGINT', () => {
            log.info('Shutting down WebUI server...');
            httpServer.stop().then(() => {
                log.info('WebUI server stopped');
                process.exit(0);
            });
        });
        process.on('SIGTERM', () => {
            log.info('Shutting down WebUI server...');
            httpServer.stop().then(() => {
                log.info('WebUI server stopped');
                process.exit(0);
            });
        });
    }
    catch (err) {
        console.error('Failed to start WebUI server:', err);
        process.exit(1);
    }
}
if (require.main === module) {
    main().catch((err) => {
        console.error('Unhandled error:', err);
        process.exit(1);
    });
}
