import { detectMatchedRule } from '../evaluation/index.js';
import { resolveWorkflowStateReference } from '../state/workflow-state-access.js';
import { waitForStepDelay } from './step-delay.js';
function isTemplateValue(value) {
    return /^\{(?:context|structured|effect):.+\}$/.test(value);
}
function resolveTemplateReference(reference, state) {
    return resolveWorkflowStateReference(reference, state);
}
function resolveTemplateString(template, state) {
    if (isTemplateValue(template)) {
        const inner = template.slice(1, -1).replace(':', '.');
        return resolveTemplateReference(inner, state);
    }
    return template.replace(/\{(context|structured|effect):([^}]+)\}/g, (_match, root, ref) => {
        const value = resolveTemplateReference(`${root}.${ref.replace(/:/g, '.')}`, state);
        if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {
            throw new Error(`Template interpolation requires scalar value for "${root}:${ref}"`);
        }
        return String(value);
    });
}
function resolveEffectPayload(effect, state) {
    return Object.fromEntries(Object.entries(effect).map(([key, value]) => {
        if (typeof value === 'string') {
            return [key, resolveTemplateString(value, state)];
        }
        return [key, value];
    }));
}
export class SystemStepExecutor {
    deps;
    runtimeState = {
        cache: new Map(),
        cleanupHandlers: new Set(),
    };
    constructor(deps) {
        this.deps = deps;
    }
    requireServices(cwd) {
        if (!this.deps.systemStepServicesFactory) {
            throw new Error('System step services are not configured');
        }
        return this.deps.systemStepServicesFactory({
            cwd,
            projectCwd: this.deps.projectCwd,
            task: this.deps.task,
            taskContext: this.deps.taskContext,
            runtimeState: this.runtimeState,
        });
    }
    cleanup() {
        for (const cleanup of this.runtimeState.cleanupHandlers) {
            cleanup();
        }
        this.runtimeState.cleanupHandlers.clear();
        this.runtimeState.cache.clear();
    }
    resolveSystemInput(services, input, state, stepName, resolutionContext) {
        return services.resolveSystemInput(input, state, stepName, resolutionContext);
    }
    async executeEffect(effect, state, cwd) {
        const payload = resolveEffectPayload(effect, state);
        const services = this.requireServices(cwd);
        return services.executeEffect(effect, payload, state);
    }
    async run(step, state) {
        await waitForStepDelay(step);
        const ruleContext = this.deps.getRuleContext(step);
        const resolvedContext = {};
        if ((step.systemInputs?.length ?? 0) > 0) {
            const services = this.requireServices(this.deps.getCwd());
            const resolutionContext = {
                cache: new Map(),
                resolvedBindings: new Map(),
            };
            for (const input of step.systemInputs ?? []) {
                const resolvedInput = this.resolveSystemInput(services, input, state, step.name, resolutionContext);
                resolvedContext[input.as] = resolvedInput;
                resolutionContext.resolvedBindings.set(input.as, resolvedInput);
            }
        }
        state.systemContexts.set(step.name, resolvedContext);
        if (step.effects && step.effects.length > 0) {
            const stepEffectResults = {};
            for (const effect of step.effects) {
                stepEffectResults[effect.type] = await this.executeEffect(effect, state, ruleContext.cwd);
                state.effectResults.set(step.name, { ...stepEffectResults });
            }
        }
        const match = await detectMatchedRule(step, '', '', {
            ...ruleContext,
            state,
        });
        const response = {
            persona: step.name,
            status: 'done',
            content: `System step "${step.name}" completed.`,
            timestamp: new Date(),
            matchedRuleIndex: match?.index,
            matchedRuleMethod: match?.method,
        };
        state.stepOutputs.set(step.name, response);
        state.lastOutput = response;
        return response;
    }
}
//# sourceMappingURL=SystemStepExecutor.js.map