/**
 * Phase 4 — LLM-Driven Code Generation (ADR-067)
 *
 * Shared utility for generating code via `claude --print` instead of
 * string templates. Each Phase 4 stage builds a prompt from SPARC output,
 * DDD model, ADRs, simulation context, and tech stack, then sends it
 * to Claude for code generation.
 *
 * Falls back to template generators when claude binary is unavailable.
 */
import { execFileSync } from 'node:child_process';
// ============================================================================
// Claude Binary Resolution (cached)
// ============================================================================
let _claudeBin; // undefined = not checked yet
function resolveClaudeBinary() {
    if (_claudeBin !== undefined)
        return _claudeBin;
    const envBin = process.env['AGENTICS_CLAUDE_BIN'];
    if (envBin) {
        _claudeBin = envBin;
        return _claudeBin;
    }
    const lookupCmd = process.platform === 'win32' ? 'where' : 'which';
    for (const candidate of ['claude', 'claude-code']) {
        try {
            const found = execFileSync(lookupCmd, [candidate], {
                stdio: ['pipe', 'pipe', 'pipe'],
                timeout: 5_000,
                encoding: 'utf-8',
            }).trim().split(/\r?\n/)[0]?.trim();
            if (found) {
                _claudeBin = found;
                return _claudeBin;
            }
        }
        catch { /* not found */ }
    }
    _claudeBin = null;
    return null;
}
/**
 * Generate code via `claude --print`.
 * Returns null code if claude binary is unavailable — caller should fall back to template.
 */
export function generateCodeViaLLM(options) {
    const start = Date.now();
    const claudeBin = resolveClaudeBinary();
    if (!claudeBin) {
        return { code: null, source: 'unavailable', durationMs: Date.now() - start };
    }
    try {
        const model = options.model ?? process.env['AGENTICS_CLAUDE_MODEL'] ?? 'claude-sonnet-4-20250514';
        const rawOutput = execFileSync(claudeBin, [
            '--print',
            '--output-format', 'text',
            '--model', model,
            options.prompt,
        ], {
            encoding: 'utf-8',
            timeout: options.timeoutMs ?? 90_000,
            maxBuffer: 10 * 1024 * 1024,
            stdio: ['pipe', 'pipe', 'pipe'],
            env: { ...process.env, MCP_SERVER_MODE: undefined },
        });
        // Strip markdown code fences if present
        let code = rawOutput.trim();
        if (code.startsWith('```')) {
            code = code.replace(/^```(?:typescript|ts|rust|json|yaml|dockerfile|makefile)?\s*\n?/, '').replace(/\n?```\s*$/, '');
        }
        if (!code || code.length < 20) {
            process.stderr.write(`[llm-codegen] ${options.label}: LLM returned empty/short output (${code.length} chars)\n`);
            return { code: null, source: 'unavailable', durationMs: Date.now() - start };
        }
        const durationMs = Date.now() - start;
        process.stderr.write(`[llm-codegen] ${options.label}: Generated ${code.length} chars in ${durationMs}ms via claude --print\n`);
        return { code, source: 'llm', durationMs };
    }
    catch (err) {
        const msg = err instanceof Error ? err.message : String(err);
        process.stderr.write(`[llm-codegen] ${options.label}: LLM generation failed: ${msg}\n`);
        return { code: null, source: 'unavailable', durationMs: Date.now() - start };
    }
}
export function formatDDDForPrompt(contexts) {
    return contexts.map(ctx => {
        const parts = [`### ${ctx.name}`];
        if (ctx.commands.length > 0) {
            parts.push('Commands:');
            for (const cmd of ctx.commands) {
                parts.push(`  - ${cmd.name}: ${cmd.description ?? ''}`);
                if (cmd.preconditions?.length)
                    parts.push(`    Preconditions: ${cmd.preconditions.join('; ')}`);
                if (cmd.input?.length)
                    parts.push(`    Input: ${cmd.input.join(', ')}`);
            }
        }
        if (ctx.queries.length > 0) {
            parts.push('Queries:');
            for (const q of ctx.queries) {
                parts.push(`  - ${q.name}: ${q.description ?? ''} → ${q.returns ?? 'unknown'}`);
                if (q.parameters?.length)
                    parts.push(`    Parameters: ${q.parameters.join(', ')}`);
            }
        }
        if (ctx.invariants.length > 0) {
            parts.push(`Invariants: ${ctx.invariants.join('; ')}`);
        }
        if (ctx.domainEvents.length > 0) {
            parts.push(`Domain Events: ${ctx.domainEvents.map(e => e.name).join(', ')}`);
        }
        return parts.join('\n');
    }).join('\n\n');
}
export function formatSimulationForPrompt(simCtx) {
    if (!simCtx || (!simCtx.scenarios.length && !simCtx.simulationId))
        return 'No simulation context available.';
    const parts = [`Simulation ID: ${simCtx.simulationId ?? 'none'}`];
    if (simCtx.scenarios.length > 0) {
        parts.push(`Scenarios (${simCtx.scenarios.length}):`);
        for (const s of simCtx.scenarios.slice(0, 5)) {
            parts.push(`  - ${s.name}: costDelta=${s.costDelta}, risk=${s.riskLevel}`);
        }
    }
    if (simCtx.costModel)
        parts.push(`Cost Model: ${JSON.stringify(simCtx.costModel).slice(0, 300)}`);
    return parts.join('\n');
}
//# sourceMappingURL=llm-codegen.js.map