/* eslint-disable no-console */
/**
 * Worker Management CLI Commands
 * Command-line interface for managing workers
 */
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
import { BaseCommand } from '../BaseCommand.js';
import { Env } from '../../config/env.js';
import { Logger } from '../../config/logger.js';
import { WorkerProjectAutoImports } from '../../runtime/WorkerProjectAutoImports.js';
import { loadWorkersModule as loadWorkersRuntimeModule } from '../../runtime/WorkersModule.js';
// Lazy initialization to prevent temporal dead zone issues
let WorkerFactory;
let WorkerRegistry;
let HealthMonitor;
let ResourceMonitor;
let workerProjectEntrypointAttempted = false;
const ensureProjectWorkerEntrypointLoaded = async () => {
    if (workerProjectEntrypointAttempted)
        return;
    workerProjectEntrypointAttempted = true;
    const result = await WorkerProjectAutoImports.tryImportProjectWorkerEntrypoint();
    if (!result.ok && result.reason === 'import-failed') {
        Logger.warn(`Project worker entrypoint import failed: ${result.errorMessage ?? 'Unknown error'}`);
    }
};
const loadWorkersModule = async () => {
    try {
        await ensureProjectWorkerEntrypointLoaded();
        return (await loadWorkersRuntimeModule());
    }
    catch (error) {
        Logger.error('Failed to load optional package "@zintrust/workers"; worker commands require this package.', error);
        throw ErrorFactory.createCliError('Optional package "@zintrust/workers" is required for worker commands. Install it to use worker:* commands.');
    }
};
const getWorkerFactory = async () => {
    if (!WorkerFactory) {
        const mod = await loadWorkersModule();
        WorkerFactory = mod.WorkerFactory;
    }
    return WorkerFactory;
};
const getWorkerRegistry = async () => {
    if (!WorkerRegistry) {
        const mod = await loadWorkersModule();
        WorkerRegistry = mod.WorkerRegistry;
    }
    return WorkerRegistry;
};
const getHealthMonitor = async () => {
    if (!HealthMonitor) {
        const mod = await loadWorkersModule();
        HealthMonitor = mod.HealthMonitor;
    }
    return HealthMonitor;
};
const getResourceMonitor = async () => {
    if (!ResourceMonitor) {
        const mod = await loadWorkersModule();
        ResourceMonitor = mod.ResourceMonitor;
    }
    return ResourceMonitor;
};
const extractStatus = (item) => {
    const status = typeof item === 'object' && item !== null ? item.status : undefined;
    if (status === 'healthy' ||
        status === 'degraded' ||
        status === 'unhealthy' ||
        status === 'critical') {
        return status;
    }
    return undefined;
};
const normalizeHealthStatuses = (summary) => {
    let list;
    if (Array.isArray(summary)) {
        list = summary;
    }
    else if (typeof summary === 'object' && summary !== null) {
        const details = summary.details;
        if (Array.isArray(details)) {
            list = details;
        }
    }
    return (list ?? [])
        .map(extractStatus)
        .filter((status) => status !== undefined);
};
/**
 * Helper: Format table output
 */
const formatTable = (headers, rows) => {
    const columnWidths = headers.map((h, i) => {
        const maxRowWidth = Math.max(...rows.map((r) => (r[i] || '').length));
        return Math.max(h.length, maxRowWidth);
    });
    const headerRow = headers.map((h, i) => h.padEnd(columnWidths[i])).join(' | ');
    const separator = columnWidths.map((w) => '-'.repeat(w)).join('-+-');
    const dataRows = rows.map((row) => row.map((cell, i) => (cell || '').padEnd(columnWidths[i])).join(' | '));
    return [headerRow, separator, ...dataRows].join('\n');
};
/**
 * Worker List Command
 */
const createWorkerListCommand = () => {
    const ext = async () => {
        try {
            const workers = await (await getWorkerFactory()).listPersisted();
            console.log(`\nTotal Workers: ${workers.length}\n`);
            if (workers.length === 0) {
                console.log('No workers found.');
                return;
            }
            const registry = await getWorkerRegistry();
            const rows = workers.map((name) => {
                const status = registry.status(name);
                return [
                    name,
                    status?.status ?? 'unknown',
                    status?.version ?? 'N/A',
                    status?.queueName ?? 'N/A',
                    String(status?.concurrency ?? 0),
                ];
            });
            console.log(formatTable(['Name', 'Status', 'Version', 'Queue', 'Concurrency'], rows));
            console.log();
        }
        catch (error) {
            Logger.error('worker:list command failed', error);
            process.exit(1);
        }
    };
    const cmd = BaseCommand.create({
        name: 'worker:list',
        description: 'List all workers',
        execute: async () => ext(),
    });
    return cmd;
};
/**
 * Worker Status Command
 */
const createWorkerStatusCommand = () => {
    const ext = async (name) => {
        try {
            if (!name) {
                Logger.error('Error: Worker name is required');
                process.exit(1);
            }
            const status = (await getWorkerRegistry()).status(name);
            const health = await (await getWorkerFactory()).getHealth(name);
            const healthData = typeof health === 'object' && health !== null
                ? health
                : {};
            const metrics = await (await getWorkerFactory()).getMetrics(name);
            console.log(`\n=== Worker: ${name} ===\n`);
            console.log(`Status: ${status?.status}`);
            console.log(`Version: ${status?.version}`);
            console.log(`Queue: ${status?.queueName}`);
            console.log(`Region: ${status?.region ?? 'N/A'}`);
            console.log(`Started: ${status?.startedAt}`);
            console.log(`Concurrency: ${status?.concurrency}`);
            console.log(`\nHealth Score: ${healthData.score ?? 'N/A'}`);
            console.log(`Health Status: ${healthData.status ?? 'N/A'}`);
            console.log(`\nMetrics:`);
            console.log(JSON.stringify(metrics, null, 2));
            console.log();
        }
        catch (error) {
            Logger.error('worker:status command failed', error);
            process.exit(1);
        }
    };
    const cmd = BaseCommand.create({
        name: 'worker:status',
        description: 'Get detailed status of a worker',
        addOptions: (command) => {
            command.argument('<name>', 'Worker name');
        },
        execute: async (options) => ext(options.args?.[0] ?? ''),
    });
    return cmd;
};
/**
 * Worker Start Command
 */
const createWorkerStartCommand = () => {
    const ext = async (name) => {
        try {
            if (!name) {
                Logger.error('Error: Worker name is required');
                process.exit(1);
            }
            await (await getWorkerFactory()).start(name);
            Logger.info(`✓ Worker "${name}" started successfully`);
        }
        catch (error) {
            Logger.error('worker:start command failed', error);
            process.exit(1);
        }
    };
    const cmd = BaseCommand.create({
        name: 'worker:start',
        description: 'Start a worker',
        addOptions: (command) => {
            command.argument('<name>', 'Worker name');
        },
        execute: async (options) => ext(options.args?.[0] ?? ''),
    });
    return cmd;
};
/**
 * Helper: Poll for persisted workers in container mode
 */
const pollForPersistedWorkers = async (factory) => {
    let workers = await factory.listPersisted();
    if (workers.length === 0 && process.env['RUNTIME_MODE'] === 'containers') {
        Logger.info('No persisted workers found. Waiting for workers to be registered... (Polling every 10s)');
        while (workers.length === 0) {
            // eslint-disable-next-line no-await-in-loop
            await new Promise((resolve) => globalThis.setTimeout(resolve, 10000));
            try {
                // eslint-disable-next-line no-await-in-loop
                workers = await factory.listPersisted();
                if (workers.length > 0) {
                    Logger.info(`Found ${workers.length} workers. Proceeding to start.`);
                }
            }
            catch (e) {
                Logger.warn('Error checking for persisted workers (retrying in 10s):', e instanceof Error ? e.message : String(e));
            }
        }
    }
    return workers;
};
const isRegisteredWorkerRunning = async (workerLike) => {
    if (typeof workerLike !== 'object' || workerLike === null)
        return false;
    const candidate = workerLike;
    const runningFn = candidate.worker?.isRunning;
    const pausedFn = candidate.worker?.isPaused;
    const isRunning = typeof runningFn === 'function' ? await Promise.resolve(runningFn()) : false;
    const isPaused = typeof pausedFn === 'function' ? pausedFn() : false;
    return isRunning && !isPaused;
};
const resolveAutoStartWorkerNames = async (factory, workersModule) => {
    const persistedRecords = await factory.listPersistedRecords();
    const fileRecords = typeof factory.listFileBackedRecords === 'function'
        ? await factory.listFileBackedRecords()
        : [];
    if (typeof workersModule.selectAutoStartNames === 'function') {
        return workersModule.selectAutoStartNames(persistedRecords, fileRecords, Logger.warn);
    }
    const persistedNames = persistedRecords
        .filter((record) => record.activeStatus !== false && record.autoStart === true)
        .map((record) => record.name);
    if (persistedNames.length > 0) {
        return { names: persistedNames, source: 'persisted' };
    }
    const seen = new Set();
    const fileNames = [];
    for (const record of fileRecords) {
        if (record.activeStatus === false || record.autoStart !== true)
            continue;
        if (seen.has(record.name))
            continue;
        seen.add(record.name);
        fileNames.push(record.name);
    }
    return { names: fileNames, source: fileNames.length > 0 ? 'file' : 'none' };
};
/**
 * Worker Start All Command
 */
const createWorkerStartAllCommand = () => {
    const ext = async () => {
        try {
            const globalAutoStart = Env.getBool('WORKER_AUTO_START', false);
            if (!globalAutoStart) {
                Logger.info('Skipping auto-start because WORKER_AUTO_START is false.');
                return;
            }
            const factory = await getWorkerFactory();
            const workersModule = await loadWorkersModule();
            const { names: workers, source } = await resolveAutoStartWorkerNames(factory, workersModule);
            if (workers.length === 0) {
                Logger.info('No auto-start eligible persisted or file-backed workers found.');
                return;
            }
            let eligibleWorkers = workers;
            if (source === 'persisted') {
                const discoveredWorkers = await pollForPersistedWorkers(factory);
                eligibleWorkers = workers.filter((name) => discoveredWorkers.includes(name));
            }
            if (eligibleWorkers.length === 0) {
                Logger.info('No auto-start eligible workers are currently available.');
                return;
            }
            const results = await Promise.all(eligibleWorkers.map(async (name) => {
                const existing = await factory.get(name);
                if (existing !== null && existing !== undefined) {
                    const trulyRunning = await isRegisteredWorkerRunning(existing);
                    if (trulyRunning) {
                        return { name, status: 'skipped' };
                    }
                    Logger.warn(`Worker "${name}" is registered but not truly running. Restarting for crash recovery.`);
                    try {
                        await factory.restart(name);
                        return { name, status: 'started' };
                    }
                    catch (error) {
                        Logger.warn(`Failed to restart stale worker "${name}"`, error);
                        return { name, status: 'failed' };
                    }
                }
                try {
                    await factory.startFromPersisted(name);
                    return { name, status: 'started' };
                }
                catch (error) {
                    Logger.warn(`Failed to start worker "${name}"`, error);
                    return { name, status: 'failed' };
                }
            }));
            const started = results.filter((result) => result.status === 'started').length;
            const skipped = results.filter((result) => result.status === 'skipped').length;
            const failed = results.filter((result) => result.status === 'failed').length;
            Logger.info('Worker start-all summary', {
                total: eligibleWorkers.length,
                started,
                skipped,
                failed,
            });
        }
        catch (error) {
            Logger.error('worker:start-all command failed', error);
            process.exit(1);
        }
    };
    const cmd = BaseCommand.create({
        name: 'worker:start-all',
        description: 'Start all persisted workers',
        execute: async () => ext(),
    });
    return cmd;
};
/**
 * Worker Stop Command
 */
const createWorkerStopCommand = () => {
    const ext = async (name) => {
        try {
            if (!name) {
                console.error('Error: Worker name is required');
                process.exit(1);
            }
            await (await getWorkerFactory()).stop(name);
            console.log(`✓ Worker "${name}" stopped successfully`);
        }
        catch (error) {
            Logger.error('worker:stop command failed', error);
            console.error(`Error: ${error.message}`);
            process.exit(1);
        }
    };
    const cmd = BaseCommand.create({
        name: 'worker:stop',
        description: 'Stop a worker',
        addOptions: (command) => {
            command.argument('<name>', 'Worker name');
        },
        execute: async (options) => ext(options.args?.[0] ?? ''),
    });
    return cmd;
};
/**
 * Worker Restart Command
 */
const createWorkerRestartCommand = () => {
    const ext = async (name) => {
        try {
            if (!name) {
                console.error('Error: Worker name is required');
                process.exit(1);
            }
            await (await getWorkerFactory()).restart(name);
            console.log(`✓ Worker "${name}" restarted successfully`);
        }
        catch (error) {
            Logger.error('worker:restart command failed', error);
            console.error(`Error: ${error.message}`);
            process.exit(1);
        }
    };
    const cmd = BaseCommand.create({
        name: 'worker:restart',
        description: 'Restart a worker',
        addOptions: (command) => {
            command.argument('<name>', 'Worker name');
        },
        execute: async (options) => ext(options.args?.[0] ?? ''),
    });
    return cmd;
};
/**
 * Worker Summary Command
 */
const createWorkerSummaryCommand = () => {
    const ext = async () => {
        try {
            const workers = (await getWorkerFactory()).list();
            const monitoringSummary = await (await getHealthMonitor()).getSummary();
            const resourceUsage = (await getResourceMonitor()).getCurrentUsage('system');
            const statuses = normalizeHealthStatuses(monitoringSummary);
            console.log(`\n=== Worker System Summary ===\n`);
            console.log(`Total Workers: ${workers.length}`);
            console.log(`\nHealth Overview:`);
            const healthCounts = {
                healthy: 0,
                degraded: 0,
                unhealthy: 0,
                critical: 0,
            };
            statuses.forEach((status) => {
                healthCounts[status]++;
            });
            console.log(`  Healthy: ${healthCounts.healthy}`);
            console.log(`  Degraded: ${healthCounts.degraded}`);
            console.log(`  Unhealthy: ${healthCounts.unhealthy}`);
            console.log(`  Critical: ${healthCounts.critical}`);
            console.log(`\nSystem Resources:`);
            console.log(`  CPU: ${resourceUsage.cpu.toFixed(1)}%`);
            console.log(`  Memory: ${resourceUsage.memory.percent.toFixed(1)}% (${(resourceUsage.memory.used /
                1024 /
                1024 /
                1024).toFixed(2)} GB used)`);
            console.log(`  Cost (hourly): $${resourceUsage.cost.hourly.toFixed(2)}`);
            console.log(`  Cost (daily): $${resourceUsage.cost.daily.toFixed(2)}`);
            console.log();
        }
        catch (error) {
            Logger.error('worker:summary command failed', error);
            process.exit(1);
        }
    };
    const cmd = BaseCommand.create({
        name: 'worker:summary',
        description: 'Get system-wide worker summary',
        execute: async () => ext(),
    });
    return cmd;
};
/**
 * Export worker command creators
 */
export const WorkerCommands = {
    createWorkerListCommand,
    createWorkerStatusCommand,
    createWorkerStartCommand,
    createWorkerStartAllCommand,
    createWorkerStopCommand,
    createWorkerRestartCommand,
    createWorkerSummaryCommand,
};
