// Minimal check harness. Every phase gate in PLAN.md is a check registered here
// and run from checks.html, so "the gate passes" is something you execute rather
// than something you assert in a commit message.

const registry = [];

export function check(phase, name, fn, options = {}) {
    registry.push({ phase, name, fn, manual: !!options.manual, slow: !!options.slow });
}

export function allChecks() {
    return registry;
}

export async function runAll({ phases = null, onResult = null, skipSlow = false } = {}) {
    const results = [];
    for (const entry of registry) {
        if (phases && !phases.includes(entry.phase)) continue;
        if (skipSlow && entry.slow) continue;

        const started = Date.now();
        let result;
        try {
            const r = await entry.fn();
            result = {
                phase: entry.phase,
                name: entry.name,
                pass: r === true || (r && r.pass !== false),
                detail: (r && r.detail) || '',
                manual: entry.manual,
                ms: Date.now() - started,
            };
        } catch (err) {
            result = {
                phase: entry.phase,
                name: entry.name,
                pass: false,
                detail: `threw: ${err && err.message ? err.message : String(err)}`,
                manual: entry.manual,
                ms: Date.now() - started,
            };
        }
        results.push(result);
        if (onResult) onResult(result);
    }
    return results;
}

export function summarize(results) {
    const total = results.length;
    const failed = results.filter((r) => !r.pass && !r.manual);
    const manual = results.filter((r) => r.manual);
    return {
        total,
        passed: results.filter((r) => r.pass).length,
        failed: failed.length,
        manual: manual.length,
        ok: failed.length === 0,
        failures: failed.map((r) => `[P${r.phase}] ${r.name}: ${r.detail}`),
    };
}

/** Assertion helpers that produce useful detail strings rather than bare booleans. */
export function expect(condition, detail) {
    return { pass: !!condition, detail };
}

export function expectClose(actual, expected, tolerance, label) {
    const diff = Math.abs(actual - expected);
    return {
        pass: diff <= tolerance,
        detail: `${label}: ${actual.toFixed(6)} vs ${expected.toFixed(6)} (Δ${diff.toFixed(6)}, tol ${tolerance})`,
    };
}

export function expectBelow(actual, limit, label) {
    return {
        pass: actual <= limit,
        detail: `${label}: ${typeof actual === 'number' ? actual.toFixed(6) : actual} (limit ${limit})`,
    };
}
