/**
 * Run Command
 *
 * Runs walkerOS flows using @walkeros/docker as a library
 * No Docker daemon required - runs directly in Node.js
 */
import path from 'path';
import { createCommandLogger, createTimer, getExecutionMode, getErrorMessage, executeRunInDocker, isDockerAvailable, } from '../../core/index.js';
import { validateMode, validateFlowFile, validatePort } from './validators.js';
import { prepareBundleForRun, isPreBuiltConfig } from './utils.js';
import { executeRunLocal } from './execution.js';
/**
 * CLI command function for `walkeros run`
 *
 * @param mode - Run mode (collect | serve)
 * @param options - Command options
 */
export async function runCommand(mode, options) {
    const timer = createTimer();
    timer.start();
    const logger = createCommandLogger(options);
    try {
        // Step 1: Validate inputs
        validateMode(mode);
        const configPath = validateFlowFile(options.config);
        if (options.port !== undefined) {
            validatePort(options.port);
        }
        // Step 2: Determine if config is pre-built or needs bundling
        const isPreBuilt = isPreBuiltConfig(configPath);
        let flowPath = null;
        if (mode === 'collect') {
            if (isPreBuilt) {
                // Use pre-built bundle directly
                flowPath = path.resolve(configPath);
                if (!options.json && !options.silent) {
                    logger.info(`📦 Using pre-built flow: ${path.basename(flowPath)}`);
                }
            }
            else {
                // Bundle JSON config first
                if (!options.json && !options.silent) {
                    logger.info('🔨 Building flow bundle...');
                }
                flowPath = await prepareBundleForRun(configPath, {
                    verbose: options.verbose,
                    silent: options.json || options.silent,
                });
                if (!options.json && !options.silent) {
                    logger.success('✅ Bundle ready');
                }
            }
        }
        // Step 3: Execute based on mode
        const executionMode = getExecutionMode(options);
        // Handle dry-run
        if (options.dryRun) {
            if (executionMode === 'docker') {
                logger.info(`[DRY-RUN] Would execute in Docker: run ${mode} with runtime image`);
            }
            else {
                logger.info(`[DRY-RUN] Would execute locally: run ${mode}`);
            }
            return;
        }
        if (executionMode === 'docker') {
            // Docker mode: Use production runtime image
            const dockerAvailable = await isDockerAvailable();
            if (!dockerAvailable) {
                throw new Error('Docker is not available. Please install Docker or use --local flag to execute locally.');
            }
            if (!options.json && !options.silent) {
                logger.info('🐳 Executing in production runtime container...');
            }
            await executeRunInDocker(mode, flowPath, {
                port: options.port,
                host: options.host,
                serveName: options.serveName,
                servePath: options.servePath,
                silent: options.silent,
            });
        }
        else {
            // Local mode: Use library functions
            if (!options.json && !options.silent) {
                const modeLabel = mode === 'collect' ? 'Collector' : 'Server';
                logger.info(`🖥️  Starting ${modeLabel} locally...`);
            }
            await executeRunLocal(mode, flowPath, {
                port: options.port,
                host: options.host,
                serveName: options.serveName,
                servePath: options.servePath,
            });
        }
        // Note: Both Docker and local modes run forever, so we won't reach here unless they fail
    }
    catch (error) {
        const duration = timer.getElapsed() / 1000;
        const errorMessage = getErrorMessage(error);
        if (options.json) {
            const output = {
                success: false,
                mode,
                error: errorMessage,
                duration,
            };
            // eslint-disable-next-line no-console
            console.log(JSON.stringify(output, null, 2));
        }
        else {
            logger.error('❌ Run failed:');
            logger.error(errorMessage);
        }
        process.exit(1);
    }
}
/**
 * Programmatic run function
 *
 * @param mode - Run mode (collect | serve)
 * @param options - Run options
 * @returns Run result
 *
 * @example
 * ```typescript
 * // Run with JSON config (bundles automatically)
 * await run('collect', {
 *   config: './flow.json',
 *   port: 8080
 * });
 *
 * // Run with pre-built bundle
 * await run('collect', {
 *   config: './flow.mjs',
 *   port: 8080
 * });
 * ```
 */
export async function run(mode, options) {
    const startTime = Date.now();
    try {
        // Validate inputs
        validateMode(mode);
        let flowFile;
        if (typeof options.config === 'string') {
            flowFile = validateFlowFile(options.config);
        }
        else {
            throw new Error('Programmatic run() requires config file path');
        }
        if (options.port !== undefined) {
            validatePort(options.port);
        }
        // Determine if config is pre-built or needs bundling
        const isPreBuilt = isPreBuiltConfig(flowFile);
        let flowPath;
        if (isPreBuilt) {
            flowPath = path.resolve(flowFile);
        }
        else {
            // Bundle JSON config
            flowPath = await prepareBundleForRun(flowFile, {
                verbose: options.verbose,
                silent: true,
            });
        }
        // Run the flow using Docker package
        await executeRunLocal(mode, flowPath, {
            port: options.port,
            host: options.host,
            serveName: options.serveName,
            servePath: options.servePath,
        });
        // Success (though runFlow runs forever, so we typically don't reach here)
        return {
            success: true,
            exitCode: 0,
            duration: Date.now() - startTime,
        };
    }
    catch (error) {
        return {
            success: false,
            exitCode: 1,
            duration: Date.now() - startTime,
            error: getErrorMessage(error),
        };
    }
}
//# sourceMappingURL=index.js.map