import * as fs from 'node:fs';
import { createRequire } from 'node:module';
import { GlobalConfigSchema } from '@olam/core/src/global-config/index.js';
import { globalConfigPath } from '@olam/core/src/global-config/store.js';
import { readConfig, writeConfig, isValidConfig, OLAM_CONFIG_PATH, } from '../lib/config.js';
const _require = createRequire(import.meta.url);
const { parse: parseWithMap } = _require('json-source-map');
/**
 * Keys settable via `olam config set`. These live in the cli/lib host-config
 * slice (`config.schema` shape) — the slice read by `olam upgrade`,
 * `olam services`, `olam auth`, and the kubectl-context resolver.
 */
const SETTABLE_KEYS = [
    'host.substrate',
    'host.kubectl_context_pinned',
    'host.gh_token',
];
/** Keys whose values are secret and must not be echoed back to the terminal. */
const SECRET_KEYS = new Set(['host.gh_token']);
/**
 * Resolve the host-config path. Honors `OLAM_CONFIG_PATH` (used by tests and
 * power-users with a non-default home); falls back to the cli/lib default
 * (`~/.olam/config.json`).
 */
function hostConfigPath() {
    return process.env['OLAM_CONFIG_PATH'] ?? OLAM_CONFIG_PATH;
}
export function registerConfig(program) {
    const config = program.command('config').description('Manage global olam configuration');
    config
        .command('validate [path]')
        .description('Validate ~/.olam/config.json (or a custom path) against the schema')
        .action((filePath) => {
        const resolvedPath = filePath ?? globalConfigPath();
        if (!fs.existsSync(resolvedPath)) {
            process.stderr.write(`config file not found: ${resolvedPath}\n`);
            process.exit(1);
        }
        let raw;
        try {
            raw = fs.readFileSync(resolvedPath, 'utf-8');
        }
        catch (err) {
            const msg = err instanceof Error ? err.message : String(err);
            process.stderr.write(`cannot read ${resolvedPath}: ${msg}\n`);
            process.exit(1);
        }
        let parsed;
        let pointers;
        try {
            const result = parseWithMap(raw);
            parsed = result.data;
            pointers = result.pointers;
        }
        catch (err) {
            const msg = err instanceof Error ? err.message : String(err);
            process.stderr.write(`${resolvedPath}: invalid JSON — ${msg}\n`);
            process.exit(1);
        }
        // `~/.olam/config.json` is shared by two schema owners: the cli/lib
        // host-config slice (`"config.schema": 1`, with host/install_id) and
        // @olam/core's global-config slice (`schemaVersion: 1`, with
        // repos/runbooks). Validate against whichever shape the file declares so
        // a healthy host-config isn't false-flagged against the repos schema.
        // (Full union validation is pending the schema-unification follow-up.)
        const isHostShape = typeof parsed === 'object' &&
            parsed !== null &&
            'config.schema' in parsed;
        if (isHostShape) {
            if (isValidConfig(parsed)) {
                process.stdout.write('valid (olam host config — config.schema v1)\n');
                process.exit(0);
            }
            process.stderr.write(`${resolvedPath}: invalid olam host config — expected { "config.schema": 1, ` +
                `host: { substrate: "compose" | "kubernetes" }, install_id: <non-empty string> }\n`);
            process.exit(1);
        }
        const result = GlobalConfigSchema.safeParse(parsed);
        if (result.success) {
            process.exit(0);
        }
        for (const issue of result.error.issues) {
            const pointer = '/' + issue.path.join('/');
            const entry = pointers[pointer];
            const rawLine = entry?.value?.line ?? entry?.key?.line ?? -1;
            const lineStr = rawLine >= 0 ? `Line ${rawLine + 1}: ` : '';
            process.stderr.write(`${lineStr}${pointer}: ${issue.message}\n`);
        }
        process.exit(1);
    });
    config
        .command('get [key]')
        .description('Print the global config (or a dotted key, e.g. host.kubectl_context_pinned)')
        .action((key) => {
        const cfg = readConfig({ configPath: hostConfigPath() });
        if (key === undefined) {
            process.stdout.write(JSON.stringify(cfg, null, 2) + '\n');
            return;
        }
        const value = key.split('.').reduce((acc, part) => {
            if (acc !== null && typeof acc === 'object' && part in acc) {
                return acc[part];
            }
            return undefined;
        }, cfg);
        if (value === undefined) {
            process.stderr.write(`${key} is not set\n`);
            process.exit(1);
        }
        process.stdout.write((typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value)) + '\n');
    });
    config
        .command('set <key> <value>')
        .description(`Set a global config value. Keys: ${SETTABLE_KEYS.join(', ')}`)
        .action((key, value) => {
        const configPath = hostConfigPath();
        if (key === 'host.substrate') {
            if (value !== 'compose' && value !== 'kubernetes') {
                process.stderr.write(`invalid value for host.substrate: "${value}" (expected "compose" or "kubernetes")\n`);
                process.exit(1);
            }
            writeConfig({ host: { substrate: value } }, { configPath });
        }
        else if (key === 'host.kubectl_context_pinned') {
            if (value.length === 0) {
                process.stderr.write('host.kubectl_context_pinned must be a non-empty context name\n');
                process.exit(1);
            }
            writeConfig({ host: { kubectl_context_pinned: value } }, { configPath });
        }
        else if (key === 'host.gh_token') {
            if (value.length === 0) {
                process.stderr.write('host.gh_token must be a non-empty token\n');
                process.exit(1);
            }
            writeConfig({ host: { gh_token: value } }, { configPath });
        }
        else {
            process.stderr.write(`unknown config key: "${key}"\n  Settable keys: ${SETTABLE_KEYS.join(', ')}\n`);
            process.exit(1);
        }
        const shown = SECRET_KEYS.has(key) ? '***' : value;
        process.stdout.write(`set ${key} = ${shown}  → ${configPath}\n`);
    });
}
//# sourceMappingURL=config.js.map