import { existsSync, readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { StatusJudgmentBuilder } from './instruction/StatusJudgmentBuilder.js';
import { getJudgmentReportFiles } from './evaluation/rule-utils.js';
import { createLogger } from '../../shared/utils/index.js';
import { buildPhaseExecutionId } from '../../shared/utils/phaseExecutionId.js';
import { recordJudgeStageSpan, runWithPhaseSpan } from './observability/workflowSpans.js';
const log = createLogger('phase-runner');
/**
 * Build the base context (shared by structured output and tag instructions).
 */
function buildBaseContext(step, ctx) {
    const reportFiles = getJudgmentReportFiles(step.outputContracts);
    if (reportFiles.length > 0) {
        const reports = [];
        for (const fileName of reportFiles) {
            const filePath = resolve(ctx.reportDir, fileName);
            if (!existsSync(filePath))
                continue;
            const content = readFileSync(filePath, 'utf-8');
            reports.push(`# ${fileName}\n\n${content}`);
        }
        if (reports.length > 0) {
            return {
                language: ctx.language,
                interactive: ctx.interactive,
                reportContent: reports.join('\n\n---\n\n'),
                inputSource: 'report',
            };
        }
        throw new Error(`Status judgment requires existing use_judge reports for step "${step.name}"`);
    }
    if (!ctx.lastResponse)
        return undefined;
    return {
        language: ctx.language,
        interactive: ctx.interactive,
        lastResponse: ctx.lastResponse,
        inputSource: 'response',
    };
}
function resolveStepProviderInfo(step, ctx) {
    if (!ctx.resolveStepProviderModel) {
        throw new Error(`Status judgment requires provider resolution for step "${step.name}"`);
    }
    return ctx.resolveStepProviderModel(step);
}
/**
 * Phase 3: Status judgment.
 *
 * Builds two instructions from the same context:
 * - Structured output instruction (JSON schema)
 * - Tag instruction (free-form tag detection)
 *
 * `judgeStatus()` tries them in order: structured → tag → ai_judge.
 */
export async function runStatusJudgmentPhase(step, ctx) {
    log.debug('Running status judgment phase', { step: step.name });
    if (!step.rules || step.rules.length === 0) {
        throw new Error(`Status judgment requires rules for step "${step.name}"`);
    }
    const rules = step.rules;
    const baseContext = buildBaseContext(step, ctx);
    if (!baseContext) {
        throw new Error(`Status judgment requires report or lastResponse for step "${step.name}"`);
    }
    const structuredInstruction = new StatusJudgmentBuilder(step, {
        ...baseContext,
        structuredOutput: true,
    }).build();
    const tagInstruction = new StatusJudgmentBuilder(step, {
        ...baseContext,
    }).build();
    if (!ctx.iteration || !Number.isInteger(ctx.iteration) || ctx.iteration <= 0) {
        throw new Error(`Status judgment requires iteration for step "${step.name}"`);
    }
    const phaseExecutionId = buildPhaseExecutionId({
        step: step.name,
        iteration: ctx.iteration,
        phase: 3,
        sequence: 1,
    });
    let didEmitPhaseStart = false;
    let resolvedPromptParts;
    const emitPhaseStart = (promptParts) => {
        resolvedPromptParts = promptParts;
        ctx.onPhaseStart?.(step, 3, 'judge', structuredInstruction, promptParts, phaseExecutionId, ctx.iteration);
        didEmitPhaseStart = true;
    };
    if (step.rules.length === 1) {
        emitPhaseStart({
            systemPrompt: '',
            userInstruction: structuredInstruction,
        });
    }
    try {
        const stepProvider = resolveStepProviderInfo(step, ctx);
        const result = await runWithPhaseSpan({
            enabled: ctx.observabilityEnabled === true,
            runId: ctx.observabilityRunId,
            workflowName: ctx.workflowName,
            step,
            iteration: ctx.iteration,
            phase: 3,
            phaseName: 'judge',
            instruction: structuredInstruction,
            phaseExecutionId,
            workflowStack: ctx.getCurrentWorkflowStack?.(),
            sanitizeText: ctx.sanitizeObservabilityText,
            providerInfo: stepProvider,
            getPromptParts: () => resolvedPromptParts,
        }, () => ctx.structuredCaller.judgeStatus(structuredInstruction, tagInstruction, rules, {
            cwd: ctx.cwd,
            stepName: step.name,
            provider: stepProvider.provider,
            resolvedProvider: stepProvider.provider,
            resolvedModel: stepProvider.model,
            language: ctx.language,
            interactive: ctx.interactive,
            onStream: ctx.onStream,
            onStructuredPromptResolved: (promptParts) => {
                if (!didEmitPhaseStart) {
                    emitPhaseStart(promptParts);
                }
            },
            onJudgeStage: (entry) => {
                recordJudgeStageSpan({
                    enabled: ctx.observabilityEnabled === true,
                    runId: ctx.observabilityRunId,
                    workflowName: ctx.workflowName,
                    step,
                    iteration: ctx.iteration,
                    phaseExecutionId,
                    workflowStack: ctx.getCurrentWorkflowStack?.(),
                    entry,
                    sanitizeText: ctx.sanitizeObservabilityText,
                });
                ctx.onJudgeStage?.(step, 3, 'judge', entry, phaseExecutionId, ctx.iteration);
            },
        }), (judgeResult) => ({
            status: 'done',
            content: `[${step.name.toUpperCase()}:${judgeResult.ruleIndex + 1}]`,
            matchedRuleIndex: judgeResult.ruleIndex,
            matchedRuleMethod: judgeResult.method,
        }));
        if (!didEmitPhaseStart) {
            throw new Error(`Missing prompt parts for phase start: ${step.name}:3`);
        }
        const tag = `[${step.name.toUpperCase()}:${result.ruleIndex + 1}]`;
        ctx.onPhaseComplete?.(step, 3, 'judge', tag, 'done', undefined, phaseExecutionId, ctx.iteration);
        return { tag, ruleIndex: result.ruleIndex, method: result.method };
    }
    catch (error) {
        const errorMsg = error instanceof Error ? error.message : String(error);
        ctx.onPhaseComplete?.(step, 3, 'judge', '', 'error', errorMsg, phaseExecutionId, ctx.iteration);
        throw error;
    }
}
//# sourceMappingURL=status-judgment-phase.js.map