/**
 * WSL2 distro import and setup.
 *
 * Handles importing a rootfs tarball into WSL2 and verifying the result.
 * The rootfs path and distro storage dir are provided by the caller —
 * this package has no opinion about where they live.
 */
import { spawn, spawnSync } from 'child_process';
import { createWriteStream, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'fs';
import { dirname, join } from 'path';
import { Readable } from 'stream';
import { finished } from 'stream/promises';
import { getAlpineRootfsDownloadUrl } from '../../../config.js';
import { log } from '../../../shared/logging/agent-log.js';
import { runSandboxSmokeTestAsync } from './smoke.js';
import { clearDetectionCache, isDistroInstalled, isWsl2Available } from './wsl-detect.js';
/**
 * Ensure the WSL2 sandbox distro is ready.
 *
 * 1. Verify WSL2 is available
 * 2. Check if distro already exists → smoke test
 * 3. Import rootfs via `wsl --import` → smoke test
 */
export async function ensureWslSandbox(options) {
    const { distro, wslDir, rootfsPath, version } = options;
    if (!isWsl2Available()) {
        return { installed: false, error: 'WSL2 is not available' };
    }
    const stampFile = join(wslDir, distro, '.rootfs-version');
    // Already installed? Check version stamp.
    if (isDistroInstalled(distro)) {
        if (version && !isRootfsStale(stampFile, version)) {
            // Version matches — already up to date, skip smoke test.
            return { installed: true };
        }
        // Stale or missing stamp — unregister and reimport.
        log.info('sandbox', `Rootfs stale or unversioned — reimporting (version=${version})`);
        const unregResult = await spawnAsync('wsl', ['--unregister', distro], 10_000);
        clearDetectionCache();
        if (unregResult.exitCode !== 0) {
            return {
                installed: false,
                error: `Rootfs update needed but failed to unregister — manual \`wsl --unregister ${distro}\` may be needed`
            };
        }
        // Fall through to re-import
    }
    // Download rootfs if not present locally, then import
    if (!existsSync(rootfsPath)) {
        if (!version) {
            return { installed: false, error: `Rootfs not found at ${rootfsPath}` };
        }
        const dlError = await downloadRootfs(rootfsPath, version);
        if (dlError) {
            return { installed: false, error: dlError };
        }
    }
    const installDir = join(wslDir, distro);
    if (!existsSync(installDir)) {
        mkdirSync(installDir, { recursive: true });
    }
    const importResult = await spawnAsync('wsl', ['--import', distro, installDir, rootfsPath, '--version', '2'], 60_000);
    if (importResult.exitCode !== 0) {
        return {
            installed: false,
            error: `WSL import failed: ${importResult.stderr.replace(/\0/g, '')}`
        };
    }
    clearDetectionCache();
    // Smoke test
    const smoke = await runSandboxSmokeTestAsync(distro);
    if (smoke.ok) {
        if (version)
            writeStamp(stampFile, version);
        return { installed: true };
    }
    const unregResult = await spawnAsync('wsl', ['--unregister', distro], 10_000);
    const unregistered = unregResult.exitCode === 0;
    clearDetectionCache();
    const failed = smoke.checks.filter((c) => !c.ok).map((c) => c.name);
    const suffix = unregistered
        ? ' (distro unregistered — retry will re-import)'
        : ' (warning: failed to unregister broken distro — manual `wsl --unregister` may be needed)';
    return {
        installed: false,
        error: `Import succeeded but smoke test failed${suffix}. Missing: ${failed.join(', ')}`
    };
}
/**
 * Enable WSL2 on a machine that doesn't have it yet.
 * Requires admin privileges (will trigger UAC prompt).
 */
export function enableWsl2() {
    const result = spawnSync('wsl', ['--install', '--no-distribution'], {
        timeout: 120_000,
        encoding: 'utf-8',
        windowsHide: true
    });
    const output = ((result.stdout ?? '') + (result.stderr ?? '')).replace(/\0/g, '');
    if (result.status === 0) {
        const needsReboot = /reboot|restart/i.test(output);
        return { success: true, needsReboot };
    }
    return { success: false, needsReboot: false, error: output || 'Failed to enable WSL2' };
}
/** Download the Alpine rootfs tarball from GitHub Releases. Returns null on success, error string on failure. */
async function downloadRootfs(rootfsPath, version) {
    if (process.env.SHORTCUT_OFFLINE === '1') {
        return `Rootfs not found at ${rootfsPath} (offline mode — cannot download)`;
    }
    const url = getAlpineRootfsDownloadUrl(version);
    const dir = dirname(rootfsPath);
    mkdirSync(dir, { recursive: true });
    const tmpPath = rootfsPath + '.downloading';
    log.info('sandbox', `Downloading Alpine rootfs from ${url}`);
    try {
        const response = await fetch(url, { signal: AbortSignal.timeout(120_000) });
        if (!response.ok) {
            return `Failed to download rootfs: HTTP ${response.status} from ${url}`;
        }
        if (!response.body) {
            return 'Failed to download rootfs: no response body';
        }
        const totalBytes = Number(response.headers.get('content-length') || 0);
        let receivedBytes = 0;
        let lastLoggedPct = -10;
        const progress = new TransformStream({
            transform(chunk, controller) {
                receivedBytes += chunk.byteLength;
                if (totalBytes > 0) {
                    const pct = Math.floor((receivedBytes / totalBytes) * 100);
                    if (pct - lastLoggedPct >= 10) {
                        lastLoggedPct = pct;
                        log.info('sandbox', `Download progress: ${pct}%`);
                    }
                }
                controller.enqueue(chunk);
            }
        });
        const fileStream = createWriteStream(tmpPath);
        await finished(Readable.fromWeb(response.body.pipeThrough(progress)).pipe(fileStream));
        renameSync(tmpPath, rootfsPath);
        log.info('sandbox', 'Alpine rootfs downloaded successfully');
        return null;
    }
    catch (err) {
        try {
            unlinkSync(tmpPath);
        }
        catch {
            /* ignore */
        }
        return `Failed to download rootfs: ${err instanceof Error ? err.message : String(err)}`;
    }
}
function isRootfsStale(stampFile, currentVersion) {
    try {
        return !existsSync(stampFile) || readFileSync(stampFile, 'utf-8').trim() !== currentVersion;
    }
    catch {
        return true;
    }
}
function writeStamp(stampFile, version) {
    try {
        writeFileSync(stampFile, version, 'utf-8');
    }
    catch (err) {
        log.warn('sandbox', 'Failed to write rootfs version stamp', err);
    }
}
/** Non-blocking spawn wrapper. */
function spawnAsync(cmd, args, timeoutMs) {
    return new Promise((resolve) => {
        const child = spawn(cmd, args, {
            stdio: ['ignore', 'pipe', 'pipe'],
            windowsHide: true
        });
        let stdout = '';
        let stderr = '';
        let settled = false;
        child.stdout?.on('data', (chunk) => {
            stdout += chunk.toString();
        });
        child.stderr?.on('data', (chunk) => {
            stderr += chunk.toString();
        });
        child.on('error', () => {
            if (!settled) {
                settled = true;
                clearTimeout(timer);
                resolve({ exitCode: null, stdout, stderr });
            }
        });
        const timer = setTimeout(() => {
            if (!settled) {
                settled = true;
                child.kill();
                resolve({ exitCode: null, stdout, stderr });
            }
        }, timeoutMs);
        child.on('close', (code) => {
            if (!settled) {
                settled = true;
                clearTimeout(timer);
                resolve({ exitCode: code, stdout, stderr });
            }
        });
    });
}
//# sourceMappingURL=wsl-setup.js.map