/**
 * Boot Orchestrator — pre-launch sequence before the MK3 TUI starts.
 *
 * Runs version check, stale-process cleanup, installation health, Docker probe,
 * and gateway bundle checks. No terminal loading UI (boot visuals are in the TUI).
 */
import { execSync } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export class BootOrchestrator {
    steps = [];
    isDevMode = false;
    constructor() {
        this.initializeSteps();
        this.detectDevMode();
    }
    initializeSteps() {
        this.steps = [
            {
                id: 'version',
                label: 'Initializing Core',
                techLabel: 'version_check :: registry_sync',
                status: 'pending',
                progress: 0,
            },
            {
                id: 'cleanup',
                label: 'Clearing Memory Space',
                techLabel: 'process_manager :: cleanup_stale',
                status: 'pending',
                progress: 0,
            },
            {
                id: 'health',
                label: 'System Integrity Check',
                techLabel: 'integrity :: gateway_bundle',
                status: 'pending',
                progress: 0,
            },
            {
                id: 'docker',
                label: 'Container Engine',
                techLabel: 'docker :: availability_check',
                status: 'pending',
                progress: 0,
            },
            {
                id: 'gateway',
                label: 'AI Gateway Systems',
                techLabel: 'gateway :: runtime_verification',
                status: 'pending',
                progress: 0,
            },
        ];
    }
    /**
     * Detect if running from dev/repo vs global install.
     * Dev mode: skip auto-updates.
     */
    detectDevMode() {
        try {
            let current = __dirname;
            for (let i = 0; i < 6; i++) {
                const gitPath = path.join(current, '.git');
                if (fs.existsSync(gitPath)) {
                    this.isDevMode = true;
                    return;
                }
                const parent = path.dirname(current);
                if (parent === current)
                    break;
                current = parent;
            }
            const pkgPath = path.join(__dirname, '..', 'package.json');
            if (fs.existsSync(pkgPath)) {
                const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
                if (pkg.workspaces) {
                    this.isDevMode = true;
                }
            }
        }
        catch {
            this.isDevMode = false;
        }
    }
    updateStep(id, status, message, progressIncrement = 0) {
        const step = this.steps.find((s) => s.id === id);
        if (!step)
            return;
        if (status === 'running' && !step.startTime) {
            step.startTime = Date.now();
            step.progress = 0;
        }
        if ((status === 'complete' || status === 'error' || status === 'warning') && !step.endTime) {
            step.endTime = Date.now();
            step.progress = 100;
        }
        step.status = status;
        if (message !== undefined) {
            step.message = message;
        }
        if (progressIncrement > 0 && step.progress !== undefined) {
            step.progress = Math.min(100, step.progress + progressIncrement);
        }
    }
    /**
     * Step 1: Version Check & Update Detection
     */
    async checkVersion() {
        this.updateStep('version', 'running');
        if (this.isDevMode) {
            this.updateStep('version', 'complete', 'Dev mode - skipping updates');
            return { needsUpdate: false };
        }
        try {
            const { isGlobalUpdateLockActive } = await import('./deferred-npm-install-lock.js');
            if (isGlobalUpdateLockActive()) {
                this.updateStep('version', 'warning', 'Update in progress — wait for updater window');
                return { needsUpdate: false };
            }
            const { checkForUpdates } = await import('./version-check.js');
            const versionInfo = await checkForUpdates('4runr-os');
            if (versionInfo.needsUpdate) {
                this.updateStep('version', 'warning', `Update available: ${versionInfo.current} → ${versionInfo.latest}`);
                return {
                    needsUpdate: true,
                    latestVersion: versionInfo.latest,
                    currentVersion: versionInfo.current,
                };
            }
            this.updateStep('version', 'complete', `v${versionInfo.current}`);
            return { needsUpdate: false, currentVersion: versionInfo.current };
        }
        catch {
            this.updateStep('version', 'warning', 'Version check failed');
            return { needsUpdate: false };
        }
    }
    /**
     * Step 2: Cleanup stale processes and locks
     */
    async cleanupStaleProcesses() {
        this.updateStep('cleanup', 'running');
        try {
            const { killStaleProcesses } = await import('./boot-sequence.js');
            const { forceClearGlobalDeferredNpmLock } = await import('./deferred-npm-install-lock.js');
            forceClearGlobalDeferredNpmLock();
            killStaleProcesses();
            await new Promise((r) => setTimeout(r, 300));
            this.updateStep('cleanup', 'complete');
        }
        catch {
            this.updateStep('cleanup', 'warning', 'Some processes may still be running');
        }
    }
    /**
     * Step 3: Health check (Gateway bundle, Prisma client under vendored gateway)
     *
     * Prefer paths relative to **this running package** (`…/4runr-os/dist/..`). Using only
     * `npm root -g` misses installs where prefix/layout differs from where `node` loaded this CLI.
     */
    async checkHealth() {
        this.updateStep('health', 'running');
        try {
            const packageRoot = path.join(__dirname, '..');
            const { ensureGatewayPrismaReady, isGatewayPrismaReady } = await import('./gateway-prisma-bootstrap.js');
            if (!isGatewayPrismaReady(packageRoot)) {
                this.updateStep('health', 'running', 'Generating Gateway Prisma client...');
                ensureGatewayPrismaReady(packageRoot);
            }
            const execGlobalRoot = () => {
                try {
                    return execSync('npm root -g', {
                        encoding: 'utf-8',
                        ...(process.platform === 'win32' ? { shell: process.env.COMSPEC || 'cmd.exe' } : {}),
                    }).trim();
                }
                catch {
                    return null;
                }
            };
            const pairs = [
                {
                    label: 'installed package',
                    gw: path.join(packageRoot, 'apps', 'gateway', 'dist', 'index.js'),
                    prisma: path.join(packageRoot, 'apps', 'gateway', 'node_modules', '.prisma', 'client'),
                },
            ];
            const gr = execGlobalRoot();
            if (gr) {
                pairs.push({
                    label: `npm root -g (${gr})`,
                    gw: path.join(gr, '4runr-os', 'apps', 'gateway', 'dist', 'index.js'),
                    prisma: path.join(gr, '4runr-os', 'apps', 'gateway', 'node_modules', '.prisma', 'client'),
                });
            }
            if (process.platform === 'win32' && process.env.APPDATA) {
                pairs.push({
                    label: '%APPDATA%\\npm\\node_modules',
                    gw: path.join(process.env.APPDATA, 'npm', 'node_modules', '4runr-os', 'apps', 'gateway', 'dist', 'index.js'),
                    prisma: path.join(process.env.APPDATA, 'npm', 'node_modules', '4runr-os', 'apps', 'gateway', 'node_modules', '.prisma', 'client'),
                });
            }
            for (const p of pairs) {
                if (fs.existsSync(p.gw) && fs.existsSync(p.prisma)) {
                    this.updateStep('health', 'complete');
                    return true;
                }
            }
            const primary = pairs[0];
            const miss = [];
            if (!fs.existsSync(primary.gw))
                miss.push(`gateway bundle (${primary.gw})`);
            if (!fs.existsSync(primary.prisma))
                miss.push(`Prisma client (${primary.prisma})`);
            const detail = `Incomplete install — missing ${miss.join(' and ')}. Often caused by a failed global npm update (EBUSY). ` +
                `Close every 4r window, stop Node (Get-Process node | Stop-Process -Force), then: npm install -g 4runr-os@latest`;
            this.updateStep('health', 'error', detail);
            return false;
        }
        catch {
            this.updateStep('health', 'error', 'Could not verify installation');
            return false;
        }
    }
    /**
     * Step 4: Docker availability check (doesn't start containers - TUI handles that)
     */
    async checkDocker() {
        this.updateStep('docker', 'running');
        try {
            execSync('docker --version', {
                stdio: 'pipe',
                timeout: 3000,
                windowsHide: true,
            });
            this.updateStep('docker', 'complete');
        }
        catch {
            this.updateStep('docker', 'warning', 'Docker not available - will run in memory mode');
        }
    }
    /**
     * Step 5: Gateway bundle verification
     */
    async checkGatewayBundle() {
        this.updateStep('gateway', 'running');
        try {
            const possiblePaths = [
                path.join(__dirname, '..', 'apps', 'gateway', 'dist', 'index.js'),
                path.join(__dirname, '..', '..', 'apps', 'gateway', 'dist', 'index.js'),
            ];
            const bundleExists = possiblePaths.some((p) => fs.existsSync(p));
            if (bundleExists) {
                this.updateStep('gateway', 'complete');
            }
            else {
                this.updateStep('gateway', 'warning', 'Gateway will start on demand');
            }
        }
        catch {
            this.updateStep('gateway', 'warning', 'Gateway verification skipped');
        }
    }
    /**
     * Main orchestration: run all boot steps (silent — TUI owns boot visuals)
     */
    async boot() {
        const versionCheck = await this.checkVersion();
        if (versionCheck.needsUpdate) {
            return {
                success: false,
                needsUpdate: true,
                updateVersion: versionCheck.latestVersion,
                steps: this.steps,
            };
        }
        await this.cleanupStaleProcesses();
        const healthOk = await this.checkHealth();
        if (!healthOk) {
            const healthStep = this.steps.find((s) => s.id === 'health');
            return {
                success: false,
                error: healthStep?.message || 'Installation health check failed',
                steps: this.steps,
            };
        }
        await this.checkDocker();
        await this.checkGatewayBundle();
        return {
            success: true,
            steps: this.steps,
        };
    }
}
export async function orchestrateBootSequence() {
    const orchestrator = new BootOrchestrator();
    return orchestrator.boot();
}
//# sourceMappingURL=boot-orchestrator.js.map