import { SYSTEM_TASK_PROTOCOL_VERSION, } from '@happier-dev/protocol';
import { SystemTaskExecutionError } from './runSystemTask.js';
export function createSystemTasksRunner(params) {
    const now = params.now ?? (() => Date.now());
    const states = new Map();
    function readState(taskId) {
        const state = states.get(taskId);
        if (!state) {
            throw new Error(`Unknown system task: ${taskId}`);
        }
        return state;
    }
    function appendEvent(taskId, input) {
        const state = readState(taskId);
        state.events.push({
            protocolVersion: SYSTEM_TASK_PROTOCOL_VERSION,
            taskId,
            tsMs: now(),
            type: input.type,
            ...(input.stepId ? { stepId: input.stepId } : {}),
            ...(input.message ? { message: input.message } : {}),
            ...(typeof input.data !== 'undefined' ? { data: redactSensitiveSystemTaskJsonValue(input.data) } : {}),
        });
    }
    return {
        async start(startParams) {
            const kind = params.kinds[startParams.kind];
            if (!kind) {
                throw new Error(`Unsupported system task kind: ${startParams.kind}`);
            }
            states.set(startParams.taskId, {
                events: [],
                result: null,
                pendingPrompt: null,
                resolvePrompt: null,
            });
            void kind.run({
                params: startParams.params,
                emit: (event) => {
                    appendEvent(startParams.taskId, event);
                },
                prompt: async (prompt) => {
                    const state = readState(startParams.taskId);
                    state.pendingPrompt = {
                        kind: prompt.kind,
                        data: redactSensitiveSystemTaskJsonValue(prompt.data),
                    };
                    appendEvent(startParams.taskId, {
                        type: 'prompt',
                        ...(prompt.stepId ? { stepId: prompt.stepId } : {}),
                        message: prompt.message,
                        data: buildPromptEventData(prompt),
                    });
                    return await new Promise((resolve) => {
                        state.resolvePrompt = (answer) => {
                            state.pendingPrompt = null;
                            state.resolvePrompt = null;
                            resolve(answer);
                        };
                    });
                },
            }).then((data) => {
                const state = readState(startParams.taskId);
                state.result = {
                    protocolVersion: SYSTEM_TASK_PROTOCOL_VERSION,
                    taskId: startParams.taskId,
                    ok: true,
                    ...(typeof data !== 'undefined' ? { data: data } : {}),
                };
            }, (error) => {
                const state = readState(startParams.taskId);
                state.result = {
                    protocolVersion: SYSTEM_TASK_PROTOCOL_VERSION,
                    taskId: startParams.taskId,
                    ok: false,
                    error: {
                        code: error instanceof SystemTaskExecutionError
                            ? error.code
                            : 'system_task_failed',
                        message: error instanceof Error ? error.message : 'System task failed',
                    },
                };
            });
            return {
                taskId: startParams.taskId,
            };
        },
        async poll(pollParams) {
            const state = readState(pollParams.taskId);
            const cursor = Math.max(0, Math.floor(pollParams.cursor));
            return {
                events: state.events.slice(cursor),
                nextCursor: state.events.length,
                result: state.result,
                pendingPrompt: state.pendingPrompt,
            };
        },
        async respond(respondParams) {
            const state = readState(respondParams.taskId);
            if (!state.resolvePrompt) {
                throw new Error(`System task ${respondParams.taskId} is not waiting for a prompt response`);
            }
            state.resolvePrompt(respondParams.answer);
            await new Promise((resolve) => setTimeout(resolve, 0));
        },
    };
}
export function buildPromptEventData(prompt) {
    const redactedData = redactSensitiveSystemTaskJsonValue(prompt.data);
    if (prompt.data && typeof prompt.data === 'object' && !Array.isArray(prompt.data)) {
        return {
            kind: prompt.kind,
            ...redactedData,
        };
    }
    return {
        kind: prompt.kind,
        value: redactedData,
    };
}
export function redactSensitiveSystemTaskJsonValue(value) {
    if (value === null) {
        return value;
    }
    switch (typeof value) {
        case 'string':
        case 'boolean':
            return value;
        case 'number':
            return Number.isFinite(value) ? value : null;
        case 'object':
            if (Array.isArray(value)) {
                return value.map((entry) => redactSensitiveSystemTaskJsonValue(entry));
            }
            return Object.fromEntries(Object.entries(value)
                .filter(([key]) => !isSensitivePromptDataKey(key))
                .map(([key, entry]) => [key, redactSensitiveSystemTaskJsonValue(entry)]));
        default:
            return null;
    }
}
const SENSITIVE_PROMPT_DATA_KEY_PATTERNS = [
    /secret/i,
    /token/i,
    /password/i,
    /statefile/i,
    /privatekeypath/i,
    /identityfile/i,
    /^env$/i,
    /cookie/i,
];
function isSensitivePromptDataKey(key) {
    const normalizedKey = String(key ?? '').trim();
    if (!normalizedKey) {
        return false;
    }
    return SENSITIVE_PROMPT_DATA_KEY_PATTERNS.some((pattern) => pattern.test(normalizedKey));
}
//# sourceMappingURL=interactiveTaskKinds.js.map