import { execa } from 'execa';
import { DEFAULT_REVIEW_INSTRUCTIONS } from '../lib/workflow.js';
import { resolveClaudeModel } from '../lib/review-models.js';
import { withTimeoutRetry } from '../lib/with-timeout-retry.js';
import { tierTimeoutMs } from './tier-timeouts.js';
const EFFORT_MAP = {
    low: 'low',
    medium: 'medium',
    high: 'high',
    max: 'max',
};
export async function runClaudeReview(repoDir, baseBranch, prTitle, quality, vendor, perReviewBudget, stepInstructions, onLog, timeoutMs, noBudgetCap, 
// Fires once after the first attempt times out, before the delayed retry.
// Split from onLog so callers (e.g. runner) can stay silent on routine
// `running: ...` chatter while still surfacing the retry signal live.
onRetry) {
    const model = resolveClaudeModel(quality, vendor);
    const effort = EFFORT_MAP[vendor.effort] ?? 'medium';
    const focusLine = quality.focus.length > 0
        ? `Focus areas: ${quality.focus.join(', ')}.`
        : '';
    const customLine = quality.custom_prompt ?? '';
    const behaviorInstructions = stepInstructions ?? DEFAULT_REVIEW_INSTRUCTIONS;
    const prompt = [
        `You are reviewing a pull request titled: "${prTitle}".`,
        `The branch \`${baseBranch}\` is the base. Review only the changes introduced in this PR.`,
        focusLine,
        customLine,
        behaviorInstructions,
    ].filter(Boolean).join('\n');
    // Omit --max-budget-usd when:
    // 1. No ANTHROPIC_API_KEY → subscription mode (claude.ai plan, budget limits don't apply)
    // 2. noBudgetCap → crazy/halfcrazy mode (explicitly uncapped run; NOT set by --no-timeout alone)
    const applyBudgetCap = !!process.env.ANTHROPIC_API_KEY && !noBudgetCap;
    const args = [
        '--print',
        '--output-format', 'json',
        '--model', model,
        '--effort', effort,
        ...(applyBudgetCap ? ['--max-budget-usd', String(perReviewBudget)] : []),
        '--allowedTools', 'Bash(git diff),Bash(git log)',
    ];
    onLog?.(`  running: claude --print --model ${model} --effort ${effort}`);
    // timeoutMs: 0 → no cap (crazy/halfcrazy); undefined → tier-based default (300/600/1200s); positive → user-specified
    const resolvedTimeout = timeoutMs === undefined ? tierTimeoutMs(quality.tier) : timeoutMs === 0 ? undefined : timeoutMs;
    try {
        const { result: { stdout }, retried } = await withTimeoutRetry(resolvedTimeout, (t) => execa('claude', args, { cwd: repoDir, timeout: t, input: prompt, env: { ...process.env } }), {
            onRetry: (effectiveMs, delayMs) => (onRetry ?? onLog)?.(`  ⏱ claude timed out at ${effectiveMs / 1000}s — waiting ${delayMs / 1000}s and retrying once`),
        });
        const raw = stdout.trim();
        try {
            const parsed = JSON.parse(raw);
            const review = typeof parsed.result === 'string' ? parsed.result.trim() : raw;
            const inputTokens = typeof parsed.usage?.input_tokens === 'number' ? parsed.usage.input_tokens : undefined;
            const outputTokens = typeof parsed.usage?.output_tokens === 'number' ? parsed.usage.output_tokens : undefined;
            const tokensUsed = inputTokens !== undefined && outputTokens !== undefined ? inputTokens + outputTokens : undefined;
            return { review, tokensUsed, inputTokens, outputTokens, model, retried };
        }
        catch {
            return { review: raw, model, retried };
        }
    }
    catch (err) {
        const execa = err;
        const rawStderr = execa.stderr?.trim() ?? '';
        const effectiveMs = execa.effectiveTimeoutMs ?? resolvedTimeout;
        const retryNote = execa.retryDelayMs !== undefined ? ' (retried once)' : '';
        const summary = execa.timedOut
            ? `timed out after ${effectiveMs !== undefined ? effectiveMs / 1000 : '?'}s${retryNote} — PR diff may be too large`
            : (rawStderr.split('\n').filter(Boolean).at(-1)) ?? execa.message ?? 'unknown error';
        const thrown = Object.assign(new Error(`claude: ${summary}`), {
            exitCode: execa.exitCode,
            timedOut: execa.timedOut,
            stderr: rawStderr,
            effectiveTimeoutMs: effectiveMs,
            retryDelayMs: execa.retryDelayMs,
        });
        throw thrown;
    }
}
export async function checkClaudeAuth() {
    try {
        const { stdout } = await execa('claude', ['--version'], { timeout: 10_000 });
        return { ok: true, detail: stdout.trim() };
    }
    catch (err) {
        const error = err;
        return { ok: false, detail: error.stderr ?? error.message ?? 'not found' };
    }
}
//# sourceMappingURL=claude.js.map