import { buildPromptBasedDecomposePrompt, buildPromptBasedMorePartsPrompt, toMorePartsResponse, } from '../team-leader-structured-output.js';
import { buildJudgePrompt, detectJudgeIndex, isValidRuleIndex, buildJudgeConditions } from '../judge-utils.js';
import { runAgent } from '../runner.js';
import { runTagJudgeStage, } from '../judge-status-usecase.js';
import { TEAM_LEADER_MAX_TURNS } from '../decompose-task-usecase.js';
import { buildPromptBasedStructuredInstruction, getErrorDetail, parseLastJsonBlock, resolveStructuredStep, } from './shared.js';
import { parseParts } from '../../core/workflow/engine/task-decomposer.js';
import { createLogger, delay, getErrorMessage } from '../../shared/utils/index.js';
import { buildMaxTurnsOption } from '../provider-call-options.js';
const log = createLogger('prompt-based-structured-caller');
const RETRY_MAX_ATTEMPTS = 3;
export const RETRY_DELAY_MS = 1000;
export class PromptBasedStructuredCaller {
    async judgeStatus(structuredInstruction, tagInstruction, rules, options) {
        if (rules.length === 0) {
            throw new Error('judgeStatus requires at least one rule');
        }
        if (rules.length === 1) {
            return { ruleIndex: 0, method: 'auto_select' };
        }
        const interactiveEnabled = options.interactive === true;
        const structuredResponse = await runAgent('conductor', buildPromptBasedStructuredInstruction(structuredInstruction), {
            cwd: options.cwd,
            provider: options.provider,
            resolvedProvider: options.resolvedProvider,
            resolvedModel: options.resolvedModel,
            ...buildMaxTurnsOption(options.provider, options.resolvedProvider, 3),
            permissionMode: 'readonly',
            language: options.language,
            onStream: options.onStream,
            onPromptResolved: options.onStructuredPromptResolved,
        });
        options.onJudgeStage?.({
            stage: 1,
            method: 'structured_output',
            status: structuredResponse.status === 'done' ? 'done' : 'error',
            instruction: structuredInstruction,
            response: structuredResponse.content,
        });
        let structuredParseError;
        if (structuredResponse.status === 'done') {
            try {
                const ruleIndex = resolveStructuredStep(parseLastJsonBlock(structuredResponse.content));
                if (isValidRuleIndex(ruleIndex, rules, interactiveEnabled)) {
                    return { ruleIndex, method: 'structured_output' };
                }
            }
            catch (error) {
                structuredParseError = getErrorDetail(error);
            }
        }
        const tagResult = await runTagJudgeStage(tagInstruction, rules, interactiveEnabled, {
            cwd: options.cwd,
            provider: options.provider,
            resolvedProvider: options.resolvedProvider,
            resolvedModel: options.resolvedModel,
            language: options.language,
            onStream: options.onStream,
            stepName: options.stepName,
        }, options.onJudgeStage);
        if (tagResult !== undefined) {
            return tagResult;
        }
        const conditions = buildJudgeConditions(rules, interactiveEnabled);
        if (conditions.length > 0) {
            let stage3Status = 'skipped';
            let stage3Instruction = '';
            let stage3Response = '';
            const fallbackIndex = await this.evaluateCondition(structuredInstruction, conditions, {
                cwd: options.cwd,
                provider: options.provider,
                resolvedProvider: options.resolvedProvider,
                resolvedModel: options.resolvedModel,
                onJudgeResponse: (entry) => {
                    stage3Status = entry.status;
                    stage3Instruction = entry.instruction;
                    stage3Response = entry.response;
                },
            });
            options.onJudgeStage?.({
                stage: 3,
                method: 'ai_judge',
                status: stage3Status,
                instruction: stage3Instruction,
                response: stage3Response,
            });
            if (isValidRuleIndex(fallbackIndex, rules, interactiveEnabled)) {
                return { ruleIndex: fallbackIndex, method: 'ai_judge' };
            }
        }
        const detail = structuredParseError == null
            ? ''
            : ` Structured response parsing failed: ${structuredParseError}`;
        throw new Error(`Status not found for step "${options.stepName}".${detail}`);
    }
    async evaluateCondition(agentOutput, conditions, options) {
        const prompt = buildJudgePrompt(agentOutput, conditions);
        const response = await runAgent(undefined, prompt, {
            cwd: options.cwd,
            provider: options.provider,
            resolvedProvider: options.resolvedProvider,
            resolvedModel: options.resolvedModel,
            ...buildMaxTurnsOption(options.provider, options.resolvedProvider, 1),
            permissionMode: 'readonly',
        });
        options.onJudgeResponse?.({
            instruction: prompt,
            status: response.status === 'done' ? 'done' : 'error',
            response: response.content,
        });
        if (response.status !== 'done') {
            return -1;
        }
        return detectJudgeIndex(response.content);
    }
    async decomposeTask(instruction, maxParts, options) {
        const prompt = buildPromptBasedDecomposePrompt(instruction, maxParts, options.language);
        return withRetry(async () => {
            const response = await runAgent(options.persona, prompt, {
                cwd: options.cwd,
                personaPath: options.personaPath,
                language: options.language,
                model: options.model,
                provider: options.provider,
                resolvedModel: options.resolvedModel,
                resolvedProvider: options.resolvedProvider,
                allowedTools: [],
                permissionMode: 'readonly',
                ...buildMaxTurnsOption(options.provider, options.resolvedProvider, TEAM_LEADER_MAX_TURNS),
                onStream: options.onStream,
                workflowMeta: options.workflowMeta,
                onPromptResolved: options.onPromptResolved,
            });
            if (response.status !== 'done') {
                const detail = response.error || response.content || response.status;
                throw new Error(`Team leader failed: ${detail}`);
            }
            return parseParts(response.content, maxParts);
        });
    }
    async requestMoreParts(originalInstruction, allResults, existingIds, maxAdditionalParts, options) {
        const prompt = buildPromptBasedMorePartsPrompt(originalInstruction, allResults, existingIds, maxAdditionalParts, options.language);
        return withRetry(async () => {
            const response = await runAgent(options.persona, prompt, {
                cwd: options.cwd,
                personaPath: options.personaPath,
                language: options.language,
                model: options.model,
                provider: options.provider,
                resolvedModel: options.resolvedModel,
                resolvedProvider: options.resolvedProvider,
                allowedTools: [],
                permissionMode: 'readonly',
                ...buildMaxTurnsOption(options.provider, options.resolvedProvider, TEAM_LEADER_MAX_TURNS),
                onStream: options.onStream,
                workflowMeta: options.workflowMeta,
            });
            if (response.status !== 'done') {
                const detail = response.error || response.content || response.status;
                throw new Error(`Team leader feedback failed: ${detail}`);
            }
            return toMorePartsResponse(parseLastJsonBlock(response.content), maxAdditionalParts);
        });
    }
}
async function withRetry(runOnce) {
    let lastError;
    for (let attempt = 1; attempt <= RETRY_MAX_ATTEMPTS; attempt++) {
        try {
            return await runOnce();
        }
        catch (error) {
            lastError = error;
            if (attempt < RETRY_MAX_ATTEMPTS) {
                log.info('Structured call failed, retrying', {
                    attempt,
                    maxAttempts: RETRY_MAX_ATTEMPTS,
                    error: getErrorMessage(error),
                });
                await delay(RETRY_DELAY_MS);
            }
        }
    }
    throw lastError instanceof Error ? lastError : new Error(getErrorMessage(lastError));
}
//# sourceMappingURL=prompt-based-structured-caller.js.map