"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runPrecheck = runPrecheck;
const child_process_1 = require("child_process");
const SUPPORTED = [
    // Ubuntu 24.04 LTS (Noble) is the primary tested target.
    { distro: 'ubuntu', minVersion: 24.04 },
    { distro: 'debian', minVersion: 12 },
];
const BEST_EFFORT = [
    { distro: 'ubuntu', minVersion: 22.04 },
    { distro: 'ubuntu', minVersion: 20.04 },
    { distro: 'debian', minVersion: 11 },
    { distro: 'rocky', minVersion: 9 },
    { distro: 'almalinux', minVersion: 9 },
    { distro: 'rhel', minVersion: 9 },
    { distro: 'fedora', minVersion: 40 },
    { distro: 'opensuse-leap', minVersion: 15.5 },
];
const UNSUPPORTED = ['alpine']; // k3s on Alpine needs extra cgroup setup, fragile
const SUPPORTED_ARCH = ['x86_64', 'amd64', 'aarch64', 'arm64'];
const REQUIRED_PORTS = [6443, 80, 443];
/**
 * Run a one-shot SSH command on the target and capture stdout. Throws on
 * non-zero exit (the caller decides whether to surface the failure as a
 * blocker or just an unknown).
 */
function ssh(target, command) {
    const result = (0, child_process_1.spawnSync)('ssh', [
        '-i', target.privateKeyPath,
        '-o', 'StrictHostKeyChecking=accept-new',
        '-o', 'ConnectTimeout=10',
        '-o', 'BatchMode=yes',
        `${target.user}@${target.host}`,
        command,
    ], { encoding: 'utf-8' });
    if (result.status !== 0) {
        throw new Error(`ssh ${target.user}@${target.host} '${command}' failed (exit ${result.status}): ${result.stderr.trim()}`);
    }
    return result.stdout.trim();
}
function safe(target, command) {
    try {
        return ssh(target, command);
    }
    catch {
        return '';
    }
}
function classify(distro, version) {
    const versionNum = parseFloat(version);
    if (UNSUPPORTED.includes(distro)) {
        return {
            compatibility: 'unsupported',
            reason: `${distro} ${version} is not supported (k3s requires extra setup)`,
        };
    }
    for (const s of SUPPORTED) {
        if (s.distro === distro && versionNum >= s.minVersion) {
            return { compatibility: 'supported' };
        }
    }
    for (const b of BEST_EFFORT) {
        if (b.distro === distro && (b.minVersion === undefined || versionNum >= b.minVersion)) {
            return {
                compatibility: 'best-effort',
                reason: `${distro} ${version} is not in the tested matrix; install will proceed but may need manual fixes`,
            };
        }
    }
    return {
        compatibility: 'unsupported',
        reason: `${distro} ${version} is unknown to Flui; for a smooth install use Ubuntu 22.04+ or Debian 12+`,
    };
}
async function runPrecheck(target) {
    // 1. Verify SSH first — reachable + we can run a command.
    ssh(target, 'echo flui-precheck-ok');
    // 2. /etc/os-release
    const osReleaseRaw = safe(target, 'cat /etc/os-release || true');
    const osVars = parseEnvBlock(osReleaseRaw);
    const distro = (osVars.ID || '').toLowerCase();
    const version = osVars.VERSION_ID || '';
    const prettyName = osVars.PRETTY_NAME || `${distro} ${version}`;
    // 3. Kernel + arch + capacity
    const kernel = safe(target, 'uname -r');
    const arch = safe(target, 'uname -m');
    const cpu = parseInt(safe(target, 'nproc') || '0', 10);
    const memoryKb = parseInt(safe(target, "awk '/MemTotal/ {print $2}' /proc/meminfo") || '0', 10);
    const memoryMb = Math.floor(memoryKb / 1024);
    const diskKb = parseInt(safe(target, "df -k --output=size / | tail -1 | tr -d ' '") || '0', 10);
    const diskGb = Math.floor(diskKb / 1024 / 1024);
    // 4. systemd present (k3s uses it)
    const hasSystemd = safe(target, 'command -v systemctl >/dev/null && echo yes || echo no') === 'yes';
    const hasCurl = safe(target, 'command -v curl >/dev/null && echo yes || echo no') === 'yes';
    const hasJq = safe(target, 'command -v jq >/dev/null && echo yes || echo no') === 'yes';
    // 5. Required ports free.
    const portsFree = REQUIRED_PORTS.map((port) => {
        const inUse = safe(target, `(ss -lnt 2>/dev/null || netstat -lnt 2>/dev/null) | awk '{print $4}' | grep -E '[:.]${port}$' | head -1`);
        return { port, free: inUse === '' };
    });
    // 6. Classify.
    const warnings = [];
    const blockers = [];
    const { compatibility, reason } = classify(distro, version);
    if (reason) {
        if (compatibility === 'unsupported')
            blockers.push(reason);
        else
            warnings.push(reason);
    }
    if (!SUPPORTED_ARCH.includes(arch)) {
        blockers.push(`unsupported architecture: ${arch} (need x86_64 or arm64)`);
    }
    if (!hasSystemd) {
        blockers.push('systemd not found — k3s installer requires systemd');
    }
    if (!hasCurl) {
        blockers.push('curl not found — install with `apt install curl` or equivalent');
    }
    if (!hasJq) {
        warnings.push('jq not found — non-fatal but recommended for the install logs');
    }
    if (cpu < 2)
        warnings.push(`only ${cpu} CPU detected — Flui needs ≥ 2`);
    if (memoryMb < 4096)
        warnings.push(`only ${memoryMb} MB RAM detected — Flui needs ≥ 4 GB`);
    if (diskGb < 30)
        warnings.push(`only ${diskGb} GB free disk on / — Flui needs ≥ 30 GB`);
    for (const p of portsFree) {
        if (!p.free)
            blockers.push(`port ${p.port} is already in use`);
    }
    return {
        os: { distro, version, prettyName },
        kernel,
        arch,
        cpu,
        memoryMb,
        diskGb,
        hasSystemd,
        hasCurl,
        hasJq,
        portsFree,
        compatibility: blockers.length > 0 ? 'unsupported' : compatibility,
        warnings,
        blockers,
    };
}
function parseEnvBlock(s) {
    const out = {};
    for (const line of s.split('\n')) {
        const m = /^([A-Z_]+)=(.*)$/.exec(line.trim());
        if (!m)
            continue;
        let value = m[2];
        if (value.startsWith('"') && value.endsWith('"'))
            value = value.slice(1, -1);
        out[m[1]] = value;
    }
    return out;
}
