"use strict";
/**
 * Owns control protocol bookkeeping (initialize + hook/permission/mcp routing)
 * shared by ``query()`` and ``createSession()``.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueryController = void 0;
class QueryController {
    constructor(transport, hooks, 
    // Lazy: Session may swap canUseTool at runtime via setCanUseTool().
    canUseToolGetter, 
    // Lazy: Session replaces its AbortController after an interrupt+continue cycle
    // (see SessionImpl.send) — a captured reference would dispatch hook / canUseTool
    // callbacks with a stale, already-aborted signal.
    abortSignalGetter) {
        this.transport = transport;
        this.canUseToolGetter = canUseToolGetter;
        this.abortSignalGetter = abortSignalGetter;
        this.hookCallbacks = new Map();
        this.registerHooks(hooks);
    }
    // ============= Initialize =============
    async initialize(opts) {
        const systemPrompt = typeof opts.systemPrompt === 'string'
            ? opts.systemPrompt
            : undefined;
        const appendSystemPrompt = typeof opts.systemPrompt === 'object'
            ? opts.systemPrompt.append
            : undefined;
        const sdkMcpServerNames = this.transport.sdkMcpServerNames;
        const initRequest = {
            subtype: 'initialize',
            hooks: this.buildHooksConfig(),
            systemPrompt,
            appendSystemPrompt,
            agents: opts.agents,
            sdkMcpServers: sdkMcpServerNames.length > 0 ? sdkMcpServerNames : undefined,
            environment: opts.environment,
            endpoint: opts.endpoint,
            capabilities: {
                askUserQuestion: true,
            },
            hasPrompt: opts.hasPrompt,
        };
        return this.transport.sendControlRequest(initRequest);
    }
    // ============= Control request routing =============
    async handleControlRequest(request) {
        const { subtype } = request.request;
        if (subtype === 'hook_callback') {
            await this.handleHookCallback(request);
        }
        else if (subtype === 'can_use_tool') {
            await this.handlePermissionRequest(request);
        }
        // mcp_message is handled at the transport level
    }
    async handlePermissionRequest(request) {
        const permRequest = request.request;
        const { tool_name, input, tool_use_id, agent_id, permission_suggestions, blocked_path, decision_reason, } = permRequest;
        const canUseTool = this.canUseToolGetter();
        if (!canUseTool) {
            this.transport.sendControlResponse(request.request_id, {
                allowed: false,
                reason: 'No permission handler provided',
                tool_use_id,
            });
            return;
        }
        try {
            const result = await canUseTool(tool_name, input, {
                signal: this.abortSignalGetter(),
                suggestions: permission_suggestions,
                blockedPath: blocked_path,
                decisionReason: decision_reason,
                toolUseID: tool_use_id,
                agentID: agent_id,
            });
            if (result.behavior === 'allow') {
                this.transport.sendControlResponse(request.request_id, {
                    allowed: true,
                    updatedInput: result.updatedInput,
                    tool_use_id,
                });
            }
            else {
                this.transport.sendControlResponse(request.request_id, {
                    allowed: false,
                    reason: result.message,
                    interrupt: result.interrupt,
                    tool_use_id,
                });
            }
        }
        catch (error) {
            this.transport.sendControlResponse(request.request_id, {
                allowed: false,
                reason: error instanceof Error ? error.message : String(error),
                tool_use_id,
            });
        }
    }
    async handleHookCallback(request) {
        const { callback_id, input, tool_use_id } = request.request;
        const callback = this.hookCallbacks.get(callback_id);
        let response = { continue: true };
        if (callback) {
            try {
                response = await callback(input, tool_use_id, { signal: this.abortSignalGetter() });
            }
            catch (error) {
                response = {
                    continue: false,
                    stopReason: error instanceof Error ? error.message : String(error),
                };
            }
        }
        this.transport.sendControlResponse(request.request_id, response);
    }
    // ============= Hooks =============
    /**
     * Replace the registered hook callbacks. The hook event structure (events,
     * matchers) was sent to CLI during initialize() — this just rewires the
     * callback functions for existing hook IDs.
     */
    setHooks(hooks) {
        this.hookCallbacks.clear();
        this.registeredHooks = undefined;
        this.registerHooks(hooks);
    }
    registerHooks(hooks) {
        if (!hooks) {
            return;
        }
        this.registeredHooks = hooks;
        for (const [event, matchers] of Object.entries(hooks)) {
            if (!matchers) {
                continue;
            }
            matchers.forEach((matcher, matcherIndex) => {
                matcher.hooks.forEach((hook, hookIndex) => {
                    const callbackId = `hook_${event}_${matcherIndex}_${hookIndex}`;
                    this.hookCallbacks.set(callbackId, hook);
                });
            });
        }
    }
    buildHooksConfig() {
        if (!this.registeredHooks) {
            return undefined;
        }
        const config = {};
        for (const [event, matchers] of Object.entries(this.registeredHooks)) {
            if (!matchers) {
                continue;
            }
            const hookEvent = event;
            config[hookEvent] = matchers.map((matcher, matcherIndex) => ({
                matcher: matcher.matcher,
                hookCallbackIds: matcher.hooks.map((_, hookIndex) => `hook_${event}_${matcherIndex}_${hookIndex}`),
                timeout: matcher.timeout,
            }));
        }
        return Object.keys(config).length > 0 ? config : undefined;
    }
}
exports.QueryController = QueryController;
//# sourceMappingURL=query-controller.js.map