import { createBasicPhaseEvent } from './phase-tracker.js';
// ---------------------------------------------------------------------------
// Chain execution
// ---------------------------------------------------------------------------
/**
 * Execute a tool chain sequentially.
 *
 * Steps with `optional: false` that fail will abort the chain.
 * Optional steps that fail are recorded but execution continues.
 *
 * @param chain      The chain definition to execute
 * @param baseParams Base parameters available to all steps (e.g. projectId, specId)
 * @param runner     Callback that dispatches tool calls
 * CHAIN EXECUTOR PATTERN: ordered tool sequence with optional/required step semantics.
 * See DESIGN_PATTERNS.md § Chain Executor Pattern.
 */
export async function executeChain(chain, baseParams, runner) {
    const chainStart = Date.now();
    const steps = [];
    const totalSteps = chain.steps.length;
    let stoppedAt;
    for (const [stepIndex, step] of chain.steps.entries()) {
        const stepStart = Date.now();
        const progress = Math.round(((stepIndex + 1) / totalSteps) * 100);
        // Build step-specific params from base params + paramMapping
        const stepParams = { ...baseParams };
        for (const [targetKey, sourceKey] of Object.entries(step.paramMapping)) {
            if (sourceKey in baseParams) {
                stepParams[targetKey] = baseParams[sourceKey];
            }
        }
        try {
            const result = await runner(step.tool, stepParams);
            steps.push({
                tool: step.tool,
                status: 'success',
                result,
                phaseEvent: createBasicPhaseEvent(step.tool, 'completed', progress),
                elapsed: Date.now() - stepStart,
            });
        }
        catch (err) {
            const errorMsg = err instanceof Error ? err.message : String(err);
            steps.push({
                tool: step.tool,
                status: 'failed',
                error: errorMsg,
                phaseEvent: createBasicPhaseEvent(step.tool, 'error', progress),
                elapsed: Date.now() - stepStart,
            });
            if (!step.optional) {
                stoppedAt = step.tool;
                break;
            }
        }
    }
    const successCount = steps.filter((s) => s.status === 'success').length;
    const anyFailed = steps.some((s) => s.status === 'failed');
    const chainStatus = stoppedAt
        ? 'failed'
        : anyFailed
            ? 'partial'
            : 'completed';
    return {
        chainId: chain.id,
        intent: chain.name,
        steps,
        summary: buildSummary(steps, totalSteps),
        globalProgress: Math.round((successCount / totalSteps) * 100),
        totalElapsed: Date.now() - chainStart,
        status: chainStatus,
        stoppedAt,
    };
}
// ---------------------------------------------------------------------------
// Result consolidation
// ---------------------------------------------------------------------------
/** Build a human-readable summary of chain execution results. */
function buildSummary(steps, totalSteps) {
    const successCount = steps.filter((s) => s.status === 'success').length;
    const failedTools = steps.filter((s) => s.status === 'failed').map((s) => s.tool);
    let summary = `${successCount}/${totalSteps} steps completed successfully.`;
    if (failedTools.length > 0) {
        summary += ` Failed: ${failedTools.join(', ')}.`;
    }
    return summary;
}
//# sourceMappingURL=chain-executor.js.map