"use strict";
/**
 * Start Command
 * Issue #96: npm install CLI support
 * Issue #125: Use getEnvPath and getPidFilePath for correct path resolution
 * Issue #136: Add --issue and --auto-port flags for worktree support
 * Start CommandMate server
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.startCommand = startCommand;
const fs_1 = require("fs");
const child_process_1 = require("child_process");
const dotenv_1 = require("dotenv");
const types_1 = require("../types");
const logger_1 = require("../utils/logger");
const daemon_1 = require("../utils/daemon");
const security_logger_1 = require("../utils/security-logger");
const paths_1 = require("../utils/paths");
const env_setup_1 = require("../utils/env-setup");
const input_validators_1 = require("../utils/input-validators");
const port_allocator_1 = require("../utils/port-allocator");
const resource_resolvers_1 = require("../utils/resource-resolvers");
const logger = new logger_1.CLILogger();
/**
 * Execute start command
 * Issue #125: Use getEnvPath and getPidFilePath for correct path resolution
 * Issue #136: Support --issue and --auto-port flags for worktree servers
 */
async function startCommand(options) {
    try {
        // Issue #136: Validate issue number if provided
        if (options.issue !== undefined) {
            const validation = (0, input_validators_1.validateIssueNoResult)(options.issue);
            if (!validation.valid) {
                logger.error(`Invalid issue number: ${validation.error}`);
                process.exit(types_1.ExitCode.START_FAILED);
                return;
            }
        }
        // Issue #125: Check for .env file at correct location
        // Issue #136: Use issue number for worktree-specific paths
        const envPath = (0, env_setup_1.getEnvPath)(options.issue);
        const pidFilePath = (0, env_setup_1.getPidFilePath)(options.issue);
        // Issue #136: Worktree-specific server label
        const serverLabel = options.issue !== undefined
            ? `Issue #${options.issue} server`
            : 'Main server';
        // Issue #136: For worktree servers, main .env must exist but worktree-specific .env is optional
        const mainEnvPath = (0, env_setup_1.getEnvPath)();
        if (!(0, fs_1.existsSync)(mainEnvPath)) {
            logger.error(`.env file not found at ${mainEnvPath}`);
            logger.info('Run "commandmate init" to create a configuration file');
            process.exit(types_1.ExitCode.CONFIG_ERROR);
            return;
        }
        const daemonManager = new daemon_1.DaemonManager(pidFilePath);
        // Issue #136: Handle auto-port allocation for worktree servers
        let port = options.port;
        if (options.autoPort && options.issue !== undefined) {
            const portAllocator = port_allocator_1.PortAllocator.getInstance();
            port = portAllocator.allocate(options.issue);
            logger.info(`Auto-allocated port ${port} for Issue #${options.issue}`);
        }
        // Issue #136: Set worktree-specific DB path
        let dbPath;
        if (options.issue !== undefined) {
            const dbResolver = new resource_resolvers_1.DbPathResolver();
            dbPath = dbResolver.resolve(options.issue);
            logger.info(`Using database: ${dbPath}`);
        }
        // Daemon mode
        if (options.daemon) {
            // Check if already running
            if (await daemonManager.isRunning()) {
                const status = await daemonManager.getStatus();
                logger.error(`${serverLabel} is already running (PID: ${status?.pid})`);
                process.exit(types_1.ExitCode.START_FAILED);
                return;
            }
            logger.info(`Starting ${serverLabel} in background...`);
            try {
                const pid = await daemonManager.start({
                    dev: options.dev,
                    port: port,
                    // Issue #136: Pass DB path for worktree servers
                    dbPath: dbPath,
                });
                logger.success(`${serverLabel} started in background (PID: ${pid})`);
                const actualPort = port || parseInt(process.env.CM_PORT || '3000', 10);
                const bind = process.env.CM_BIND || '127.0.0.1';
                const url = `http://${bind === '0.0.0.0' ? '127.0.0.1' : bind}:${actualPort}`;
                logger.info(`URL: ${url}`);
                (0, security_logger_1.logSecurityEvent)({
                    timestamp: new Date().toISOString(),
                    command: 'start',
                    action: 'success',
                    details: `Daemon started (PID: ${pid})${options.issue !== undefined ? ` (Issue #${options.issue})` : ''}`,
                });
                process.exit(types_1.ExitCode.SUCCESS);
            }
            catch (error) {
                const message = (0, types_1.getErrorMessage)(error);
                logger.error(`Failed to start daemon: ${message}`);
                (0, security_logger_1.logSecurityEvent)({
                    timestamp: new Date().toISOString(),
                    command: 'start',
                    action: 'failure',
                    details: message,
                });
                process.exit(types_1.ExitCode.START_FAILED);
            }
            return;
        }
        // Foreground mode (default)
        const npmScript = options.dev ? 'dev' : 'start';
        logger.info(`Starting ${serverLabel} in foreground (${options.dev ? 'development' : 'production'} mode)...`);
        // Issue #125: Load .env file from correct location (same as daemon mode)
        // Issue #136: Load main .env first, then overlay worktree-specific .env if exists
        const mainEnvResult = (0, dotenv_1.config)({ path: mainEnvPath });
        let envResult = mainEnvResult;
        if (options.issue !== undefined && (0, fs_1.existsSync)(envPath) && envPath !== mainEnvPath) {
            envResult = (0, dotenv_1.config)({ path: envPath, override: true });
        }
        if (mainEnvResult.error) {
            logger.warn(`Failed to load .env file at ${mainEnvPath}: ${mainEnvResult.error.message}`);
            logger.info('Continuing with existing environment variables');
        }
        // Build environment by merging process.env with .env values
        const env = {
            ...process.env,
            ...(mainEnvResult.parsed || {}),
            ...(envResult.parsed || {}),
        };
        // Command line options override .env values
        if (port) {
            env.CM_PORT = String(port);
        }
        // Issue #136: Set DB path for worktree servers
        if (dbPath) {
            env.CM_DB_PATH = dbPath;
        }
        // Issue #125: Security warnings for external access
        const bindAddress = env.CM_BIND || '127.0.0.1';
        const authToken = env.CM_AUTH_TOKEN;
        if (bindAddress === '0.0.0.0') {
            logger.warn('WARNING: Server is accessible from external networks (CM_BIND=0.0.0.0)');
            if (!authToken) {
                logger.warn('SECURITY WARNING: No authentication token configured. External access is not recommended without CM_AUTH_TOKEN.');
                logger.info('Run "commandmate init" to configure a secure authentication token.');
            }
        }
        // Use package installation directory, not current working directory
        const packageRoot = (0, paths_1.getPackageRoot)();
        const child = (0, child_process_1.spawn)('npm', ['run', npmScript], {
            cwd: packageRoot,
            env,
            stdio: 'inherit',
        });
        child.on('error', (err) => {
            logger.error(`Failed to start server: ${err.message}`);
            (0, security_logger_1.logSecurityEvent)({
                timestamp: new Date().toISOString(),
                command: 'start',
                action: 'failure',
                details: err.message,
            });
            process.exit(types_1.ExitCode.START_FAILED);
        });
        child.on('close', (code) => {
            const exitCode = code ?? 0;
            (0, security_logger_1.logSecurityEvent)({
                timestamp: new Date().toISOString(),
                command: 'start',
                action: exitCode === 0 ? 'success' : 'failure',
                details: `Server exited with code ${exitCode}`,
            });
            process.exit(exitCode);
        });
    }
    catch (error) {
        const message = (0, types_1.getErrorMessage)(error);
        logger.error(`Start failed: ${message}`);
        (0, security_logger_1.logSecurityEvent)({
            timestamp: new Date().toISOString(),
            command: 'start',
            action: 'failure',
            details: message,
        });
        process.exit(types_1.ExitCode.UNEXPECTED_ERROR);
    }
}
