/**
 * Daemon startup preflight: verify the better-sqlite3 native binding loads
 * against the current Node.js version.
 *
 * If the binding was compiled for a different Node.js version
 * (NODE_MODULE_VERSION mismatch), we attempt `npm rebuild better-sqlite3`
 * in the nexus-prime package root, then retry the binding load.
 *
 * On unrecoverable failure → write startup-error.json to stateRoot and
 * return { ok: false }.
 */
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';
import { spawn } from 'child_process';
const VERSION_MISMATCH_RE = /NODE_MODULE_VERSION|was compiled against a different/i;
/** Resolve the nexus-prime package root (the dir containing package.json). */
function resolveInstallDir() {
    // dist/daemon/preflight.js  →  ../../..  = package root
    // src/daemon/preflight.ts   →  ../../..  = same (tsx runs from same depth)
    return path.resolve(fileURLToPath(import.meta.url), '..', '..', '..');
}
function writeStartupError(stateRoot, result) {
    try {
        fs.mkdirSync(stateRoot, { recursive: true });
        const payload = { ...result, at: Date.now() };
        fs.writeFileSync(path.join(stateRoot, 'startup-error.json'), JSON.stringify(payload, null, 2));
    }
    catch {
        // ignore write failure — we're already in the error path
    }
}
/**
 * Run `npm rebuild better-sqlite3` in installDir with a 60-second timeout.
 * Returns true if the child exited 0.
 */
function rebuildSqlite(installDir) {
    return new Promise((resolve) => {
        const child = spawn('npm', ['rebuild', 'better-sqlite3'], {
            cwd: installDir,
            stdio: 'pipe',
            env: process.env,
        });
        const timeout = setTimeout(() => {
            child.kill('SIGTERM');
            resolve(false);
        }, 60_000);
        child.on('close', (code) => {
            clearTimeout(timeout);
            resolve(code === 0);
        });
        child.on('error', () => {
            clearTimeout(timeout);
            resolve(false);
        });
    });
}
/**
 * Test the native binding by opening an in-memory database.
 * Returns null on success, the error on failure.
 */
async function testBinding() {
    try {
        // Dynamic import so the error is catchable per invocation.
        const { default: Database } = await import('better-sqlite3');
        const db = new Database(':memory:');
        db.close();
        return null;
    }
    catch (err) {
        return err instanceof Error ? err : new Error(String(err));
    }
}
/**
 * Run the preflight check.
 * Returns { ok: true } if the binding works after at most one rebuild attempt.
 * Returns { ok: false, code, hint } and writes startup-error.json on failure.
 */
export async function runPreflight(stateRoot) {
    const err = await testBinding();
    if (!err)
        return { ok: true, at: Date.now() };
    if (!VERSION_MISMATCH_RE.test(err.message)) {
        // Not a version-mismatch error — surface as-is
        const result = {
            ok: false,
            code: 'sqlite-load-failed',
            hint: `better-sqlite3 failed to load: ${err.message}. Try: npm rebuild better-sqlite3`,
            at: Date.now(),
        };
        writeStartupError(stateRoot, result);
        return result;
    }
    console.error('[nexus-preflight] NODE_MODULE_VERSION mismatch detected — rebuilding better-sqlite3 …');
    const installDir = resolveInstallDir();
    const rebuilt = await rebuildSqlite(installDir);
    if (!rebuilt) {
        const result = {
            ok: false,
            code: 'sqlite-rebuild-failed',
            hint: `npm rebuild better-sqlite3 failed. Run it manually in ${installDir}, then restart nexus-prime.`,
            at: Date.now(),
        };
        writeStartupError(stateRoot, result);
        return result;
    }
    // Retry load after rebuild
    const err2 = await testBinding();
    if (!err2) {
        console.error('[nexus-preflight] Rebuild succeeded — native binding loaded.');
        return { ok: true, at: Date.now() };
    }
    const result = {
        ok: false,
        code: 'sqlite-rebuild-failed',
        hint: `better-sqlite3 still fails after rebuild: ${err2.message}`,
        at: Date.now(),
    };
    writeStartupError(stateRoot, result);
    return result;
}
