import { writeFileSync } from 'node:fs';
import { readGlobalOptions } from '../shared/shared.utils.js';
import { Command } from 'commander';
import { currentGateCliRoot } from './branch-local-cli.js';
const PROVIDER_MARKERS = [
    { runtime: 'claude', keys: ['CLAUDECODE'] },
    { runtime: 'cursor', keys: ['CURSOR_AGENT'] },
    { runtime: 'codex', keys: ['CODEX_THREAD_ID', 'CODEX_SESSION_ID'] },
];
const PROVIDER_MODEL_EVIDENCE_KEYS = {
    claude: ['ANTHROPIC_MODEL', 'CLAUDE_MODEL'],
    cursor: ['CURSOR_MODEL'],
    codex: ['CODEX_MODEL'],
};
function nonEmptyEnvValue(env, key) {
    const value = env[key]?.trim();
    return value ? value : undefined;
}
function fallbackRoute(canAwait, reason) {
    return canAwait
        ? { route: 'delegate-sync', reason }
        : { route: 'refuse', reason };
}
export function resolveGateRoute(input) {
    const expectedRuntime = input.expectRuntime.trim().toLowerCase();
    const expectedModel = input.expectModel.trim();
    const activeMarkers = PROVIDER_MARKERS.flatMap(({ keys, runtime }) => {
        const activeKeys = keys.filter((key) => nonEmptyEnvValue(input.env, key));
        return activeKeys.length > 0 ? [{ keys: activeKeys, runtime }] : [];
    });
    const expectedRuntimeMarker = activeMarkers.find(({ runtime }) => runtime === expectedRuntime);
    if (!expectedRuntimeMarker && activeMarkers.length !== 1) {
        return fallbackRoute(input.canAwait, activeMarkers.length === 0
            ? 'No provider runtime marker is available; inline reviewer identity is ambiguous.'
            : `Multiple provider runtime markers are present (${activeMarkers.flatMap(({ keys }) => keys).join(', ')}), but none identifies expected runtime ${expectedRuntime}.`);
    }
    if (!expectedRuntimeMarker) {
        const activeRuntime = activeMarkers[0].runtime;
        return fallbackRoute(input.canAwait, `Provider runtime marker identifies ${activeRuntime}, not expected runtime ${expectedRuntime}.`);
    }
    const providerModelEvidenceKeys = expectedRuntime in PROVIDER_MODEL_EVIDENCE_KEYS
        ? PROVIDER_MODEL_EVIDENCE_KEYS[expectedRuntime]
        : [];
    const modelEvidence = providerModelEvidenceKeys.flatMap((key) => {
        const value = nonEmptyEnvValue(input.env, key);
        return value ? [{ key, value }] : [];
    });
    const enforceExpectedModel = expectedModel !== 'unknown' && expectedModel !== 'provider-default';
    const contradictoryModel = enforceExpectedModel
        ? modelEvidence.find(({ value }) => value !== expectedModel)
        : undefined;
    if (contradictoryModel) {
        return fallbackRoute(input.canAwait, `Model evidence ${contradictoryModel.key}=${contradictoryModel.value} contradicts expected model ${expectedModel}.`);
    }
    return {
        route: 'inline',
        reason: modelEvidence.length > 0
            ? `Provider runtime marker matches expected runtime ${expectedRuntime}; available model evidence matches ${expectedModel}.`
            : `Provider runtime marker matches expected runtime ${expectedRuntime}; model evidence is unavailable.`,
    };
}
function parseRequiredOption(value, name) {
    const parsed = value?.trim();
    if (!parsed) {
        throw new Error(`${name} must be a non-empty string.`);
    }
    return parsed;
}
function parseCanAwait(value) {
    if (value === 'true') {
        return true;
    }
    if (value === 'false') {
        return false;
    }
    throw new Error('--can-await must be true or false.');
}
export function createGateRouteCommand(dependencies) {
    return new Command('route')
        .description('Choose a headless-safe reviewer execution route')
        .requiredOption('--expect-runtime <runtime>', 'Expected reviewer runtime from gate invocation metadata')
        .requiredOption('--expect-model <model>', 'Expected reviewer model from gate invocation metadata')
        .requiredOption('--can-await <boolean>', 'Whether the host can synchronously await a delegated reviewer')
        .option('--json', 'Print the route decision as JSON')
        .action((options, command) => {
        const context = dependencies.buildCommandContext(readGlobalOptions(command));
        const expectedRuntime = parseRequiredOption(options.expectRuntime, '--expect-runtime');
        const decision = resolveGateRoute({
            expectRuntime: expectedRuntime,
            expectModel: parseRequiredOption(options.expectModel, '--expect-model'),
            canAwait: parseCanAwait(options.canAwait),
            env: dependencies.processEnv,
        });
        if (context.json) {
            const envelope = {
                ...decision,
                cliRoot: dependencies.cliRoot ?? currentGateCliRoot(),
            };
            const receiptPath = dependencies.processEnv.OAT_GATE_ROUTE_RECEIPT_PATH;
            if (receiptPath) {
                writeFileSync(receiptPath, `${JSON.stringify({ ...envelope, runtime: expectedRuntime })}\n`, { mode: 0o600 });
            }
            context.logger.json(envelope);
        }
        else {
            context.logger.info(`${decision.route}: ${decision.reason}`);
        }
    });
}
