/**
 * commands/detect-runtime.mjs — `apt-tools detect-runtime <projectDir>`.
 *
 * Exposes runtime-detect.mjs at the CLI surface so adopters can preview
 * which driver Aperant will pick for /apt:verify-proof.
 *
 * Returns:
 *   { status: 'ok', command: 'detect-runtime', projectDir,
 *     runtime: { is_electron, is_tauri, is_nextjs, is_web_frontend, ... },
 *     selected_driver_id: string | null,
 *     fallback_attempts: [{ driver_id, reason }] }
 */
import { existsSync, readdirSync, readFileSync } from 'node:fs';
import { join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { err, ok } from '../util/result.mjs';
import { resolveDriver } from '../verify-proof/resolver.mjs';
import { loadRuntimeCapabilities } from '../verify-proof/runtime-detect.mjs';
/** Default required capabilities — the smallest set that proves a driver is usable. */
const DEFAULT_REQUIRED_CAPABILITIES = ['screenshot'];
/**
 * Discover every driver manifest bundled with @aperant/framework.
 * @param {string} frameworkRoot — absolute path to packages/framework or .aperant/deps/.../@aperant/framework
 * @returns {Array<object>}
 */
function discoverBundledDrivers(frameworkRoot) {
    const dir = join(frameworkRoot, 'drivers');
    if (!existsSync(dir))
        return [];
    const manifests = [];
    for (const entry of readdirSync(dir, { withFileTypes: true })) {
        if (!entry.isDirectory())
            continue;
        const manifestPath = join(dir, entry.name, 'manifest.json');
        if (!existsSync(manifestPath))
            continue;
        try {
            const parsed = JSON.parse(readFileSync(manifestPath, 'utf-8'));
            manifests.push({ ...parsed, locality: 'bundled' });
        }
        catch {
            /* skip malformed manifests */
        }
    }
    return manifests;
}
/**
 * Discover every user-installed driver manifest at .aperant/drivers/.
 * @param {string} projectDir
 * @returns {Array<object>}
 */
function discoverUserDrivers(projectDir) {
    const dir = join(projectDir, '.aperant/drivers');
    if (!existsSync(dir))
        return [];
    const manifests = [];
    for (const entry of readdirSync(dir, { withFileTypes: true })) {
        if (!entry.isDirectory())
            continue;
        const manifestPath = join(dir, entry.name, 'manifest.json');
        if (!existsSync(manifestPath))
            continue;
        try {
            const parsed = JSON.parse(readFileSync(manifestPath, 'utf-8'));
            manifests.push({ ...parsed, locality: 'user' });
        }
        catch {
            /* skip malformed manifests */
        }
    }
    return manifests;
}
/**
 * @param {string} projectDir
 * @param {string[]} [_extra]
 */
export function cmdDetectRuntime(projectDir, _extra = []) {
    if (!projectDir)
        return err('Usage: apt-tools detect-runtime <project-dir>');
    const target = resolve(projectDir);
    // Read user config (used both for the monorepo walk + override).
    let monorepoGlobs;
    let override = [];
    const configPath = join(target, '.aperant/config.json');
    if (existsSync(configPath)) {
        try {
            const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));
            if (Array.isArray(cfg?.verification?.monorepo_globs)) {
                monorepoGlobs = cfg.verification.monorepo_globs.filter((x) => typeof x === 'string');
            }
            if (Array.isArray(cfg?.verification?.runtimes)) {
                override = cfg.verification.runtimes.filter((x) => typeof x === 'string');
            }
        }
        catch {
            /* malformed config — ignore */
        }
    }
    // Detect runtime capabilities from project's package.json + (optionally)
    // monorepo `apps/*` walk. Default behaviour matches the canonical
    // Aperant layout — adopters opt out via verification.monorepo_globs: [].
    const runtime = loadRuntimeCapabilities(target, monorepoGlobs !== undefined ? { monorepo_globs: monorepoGlobs } : undefined);
    // Discover bundled + user drivers.
    // __dirname-equivalent under ESM: walk up from this file to the framework
    // package root. fileURLToPath is portable across POSIX + Windows;
    // new URL(...).pathname returns '/C:/...' on Windows which resolve()
    // does not handle correctly.
    const frameworkRoot = fileURLToPath(new URL('../../..', import.meta.url));
    const bundled = discoverBundledDrivers(frameworkRoot);
    const user = discoverUserDrivers(target);
    const drivers = [...bundled, ...user];
    // Try resolving with the default minimum required capability.
    let selected = null;
    let fallback_attempts = [];
    try {
        const result = resolveDriver({
            drivers,
            runtime,
            required_capabilities: DEFAULT_REQUIRED_CAPABILITIES,
            override,
        });
        selected = result.selected.driverId;
        fallback_attempts = result.fallback_attempts;
    }
    catch (resolveErr) {
        fallback_attempts = resolveErr && Array.isArray(resolveErr.attempts) ? resolveErr.attempts : [];
    }
    return ok({
        status: 'ok',
        command: 'detect-runtime',
        projectDir: target,
        runtime,
        discovered_drivers: drivers.map((d) => ({
            driverId: d.driverId,
            version: d.version,
            locality: d.locality,
        })),
        selected_driver_id: selected,
        fallback_attempts,
    });
}
//# sourceMappingURL=detect-runtime.mjs.map