/**
 * MCP Elicitation Protocol
 *
 * Protocol-level interface for the MCP elicitation system that enables
 * tools to request interactive user input during execution.
 *
 * This module provides:
 * - Protocol message types for MCP elicitation requests/responses
 * - Protocol-level handlers for different transport types
 * - Utility functions for protocol message construction
 * - Integration with the ElicitationManager
 *
 * Implements MCP 2024-11-05 elicitation specification.
 *
 * @module mcp/elicitationProtocol
 * @since 8.39.0
 */
import { randomUUID } from "crypto";
import { logger } from "../utils/logger.js";
import { withTimeout } from "../utils/async/withTimeout.js";
import { globalElicitationManager, } from "./elicitation/elicitationManager.js";
/**
 * Create an elicitation request protocol message
 */
export function createElicitationRequest(params) {
    return {
        jsonrpc: "2.0",
        id: randomUUID(),
        method: "elicitation/request",
        params: {
            type: params.type,
            message: params.message,
            toolName: params.toolName,
            serverId: params.serverId,
            timeout: params.timeout,
            optional: params.optional,
            defaultValue: params.defaultValue,
            options: params.options ?? {},
        },
    };
}
/**
 * Create an elicitation response protocol message
 */
export function createElicitationResponse(requestId, response) {
    return {
        jsonrpc: "2.0",
        id: randomUUID(),
        method: "elicitation/response",
        params: {
            requestId,
            responded: response.responded,
            value: response.value,
            cancelled: response.cancelled,
            timedOut: response.timedOut,
            error: response.error,
        },
    };
}
/**
 * Create an elicitation cancel protocol message
 */
export function createElicitationCancel(requestId, reason) {
    return {
        jsonrpc: "2.0",
        id: randomUUID(),
        method: "elicitation/cancel",
        params: {
            requestId,
            reason,
        },
    };
}
/**
 * Check if a message is an elicitation protocol message
 */
export function isElicitationProtocolMessage(message) {
    if (typeof message !== "object" || message === null) {
        return false;
    }
    const msg = message;
    return (msg.jsonrpc === "2.0" &&
        typeof msg.id === "string" &&
        (msg.method === "elicitation/request" ||
            msg.method === "elicitation/response" ||
            msg.method === "elicitation/cancel") &&
        typeof msg.params === "object" &&
        msg.params !== null);
}
/**
 * Convert protocol message to Elicitation type
 */
export function protocolMessageToElicitation(message) {
    const { type, message: displayMessage, toolName, serverId, timeout, optional, defaultValue, options, } = message.params;
    const base = {
        id: message.id,
        type,
        message: displayMessage,
        toolName,
        serverId,
        timeout,
        optional,
        defaultValue,
    };
    // Add type-specific options
    switch (type) {
        case "confirmation":
            return {
                ...base,
                type: "confirmation",
                confirmLabel: options?.confirmLabel,
                cancelLabel: options?.cancelLabel,
            };
        case "text":
            return {
                ...base,
                type: "text",
                placeholder: options?.placeholder,
                minLength: options?.minLength,
                maxLength: options?.maxLength,
                pattern: options?.pattern,
                multiline: options?.multiline,
            };
        case "select":
            return {
                ...base,
                type: "select",
                options: options?.options ?? [],
            };
        case "multiselect":
            return {
                ...base,
                type: "multiselect",
                options: options?.options ?? [],
                minSelections: options?.minSelections,
                maxSelections: options?.maxSelections,
            };
        case "form":
            return {
                ...base,
                type: "form",
                fields: options?.fields ?? [],
                submitLabel: options?.submitLabel,
            };
        case "file":
            return {
                ...base,
                type: "file",
                accept: options?.accept,
                multiple: options?.multiple,
                maxSize: options?.maxSize,
            };
        case "secret":
            return {
                ...base,
                type: "secret",
                hint: options?.hint,
            };
        default:
            return base;
    }
}
/**
 * Convert ElicitationResponse to protocol message
 */
export function elicitationResponseToProtocol(response) {
    return createElicitationResponse(response.requestId, {
        responded: response.responded,
        value: response.value,
        cancelled: response.cancelled,
        timedOut: response.timedOut,
        error: response.error,
    });
}
/**
 * Elicitation Protocol Adapter
 *
 * Bridges protocol-level messages with the ElicitationManager
 */
export class ElicitationProtocolAdapter {
    manager;
    config;
    constructor(config = {}) {
        this.manager = config.manager ?? globalElicitationManager;
        this.config = {
            manager: this.manager,
            defaultTimeout: config.defaultTimeout ?? 60000,
            enableLogging: config.enableLogging ?? false,
            customHandler: config.customHandler,
        };
    }
    /**
     * Handle incoming protocol message
     */
    async handleMessage(message) {
        if (this.config.enableLogging) {
            logger.info("[ElicitationProtocol] Received:", message.method);
        }
        // Use custom handler if provided
        if (this.config.customHandler) {
            return await withTimeout(this.config.customHandler(message), this.config.defaultTimeout, `[ElicitationProtocol] Custom handler timed out after ${this.config.defaultTimeout}ms`);
        }
        switch (message.method) {
            case "elicitation/request":
                return this.handleRequest(message);
            case "elicitation/response":
                return this.handleResponse(message);
            case "elicitation/cancel":
                return this.handleCancel(message);
            default:
                if (this.config.enableLogging) {
                    logger.warn(`[ElicitationProtocol] Unhandled method: ${message.method}`);
                }
                return;
        }
    }
    /**
     * Handle elicitation request
     */
    async handleRequest(message) {
        const elicitation = protocolMessageToElicitation(message);
        // Use the manager to process the request
        const response = await this.manager.request({
            ...elicitation,
            timeout: elicitation.timeout ?? this.config.defaultTimeout,
        });
        return elicitationResponseToProtocol(response);
    }
    /**
     * Handle elicitation response (for external responses)
     */
    async handleResponse(_message) {
        // Responses are typically handled by the manager internally
        // This is for external systems sending responses
        if (this.config.enableLogging) {
            logger.info("[ElicitationProtocol] Response received (no action needed)");
        }
    }
    /**
     * Handle elicitation cancel
     */
    async handleCancel(message) {
        this.manager.cancel(message.params.requestId, message.params.reason);
    }
    /**
     * Send an elicitation request through the protocol
     */
    async requestElicitation(params) {
        const message = createElicitationRequest(params);
        const elicitation = protocolMessageToElicitation(message);
        return this.manager.request({
            ...elicitation,
            timeout: elicitation.timeout ?? this.config.defaultTimeout,
        });
    }
    /**
     * Cancel a pending elicitation
     */
    cancelElicitation(requestId, reason) {
        this.manager.cancel(requestId, reason);
    }
    /**
     * Get the underlying manager
     */
    getManager() {
        return this.manager;
    }
    /**
     * Set protocol handler for the manager
     */
    setHandler(handler) {
        this.manager.setHandler(handler);
    }
    /**
     * Enable/disable the protocol
     */
    setEnabled(enabled) {
        this.manager.setEnabled(enabled);
    }
    /**
     * Check if protocol is enabled
     */
    isEnabled() {
        return this.manager.isEnabled();
    }
}
/**
 * Create protocol-compliant confirmation request
 */
export function createConfirmationRequest(message, options) {
    const requestOptions = {};
    if (options.confirmLabel !== undefined) {
        requestOptions.confirmLabel = options.confirmLabel;
    }
    if (options.cancelLabel !== undefined) {
        requestOptions.cancelLabel = options.cancelLabel;
    }
    return createElicitationRequest({
        type: "confirmation",
        message,
        toolName: options.toolName,
        serverId: options.serverId,
        timeout: options.timeout,
        options: requestOptions,
    });
}
/**
 * Create protocol-compliant text input request
 */
export function createTextInputRequest(message, options) {
    const requestOptions = {};
    if (options.placeholder !== undefined) {
        requestOptions.placeholder = options.placeholder;
    }
    if (options.minLength !== undefined) {
        requestOptions.minLength = options.minLength;
    }
    if (options.maxLength !== undefined) {
        requestOptions.maxLength = options.maxLength;
    }
    if (options.pattern !== undefined) {
        requestOptions.pattern = options.pattern;
    }
    if (options.multiline !== undefined) {
        requestOptions.multiline = options.multiline;
    }
    return createElicitationRequest({
        type: "text",
        message,
        toolName: options.toolName,
        serverId: options.serverId,
        defaultValue: options.defaultValue,
        timeout: options.timeout,
        options: requestOptions,
    });
}
/**
 * Create protocol-compliant select request
 */
export function createSelectRequest(message, selectOptions, options) {
    return createElicitationRequest({
        type: "select",
        message,
        toolName: options.toolName,
        serverId: options.serverId,
        defaultValue: options.defaultValue,
        timeout: options.timeout,
        options: {
            options: selectOptions,
        },
    });
}
/**
 * Create protocol-compliant form request
 */
export function createFormRequest(message, fields, options) {
    const requestOptions = {
        fields: fields,
    };
    if (options.submitLabel !== undefined) {
        requestOptions.submitLabel = options.submitLabel;
    }
    return createElicitationRequest({
        type: "form",
        message,
        toolName: options.toolName,
        serverId: options.serverId,
        timeout: options.timeout,
        options: requestOptions,
    });
}
/**
 * Global protocol adapter instance
 */
export const globalElicitationProtocol = new ElicitationProtocolAdapter();
