"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createChat = void 0;
/* eslint-disable prefer-const */
/**
 * @fileoverview
 * Core module for the Q Chat Client that initializes the chat interface and establishes
 * bidirectional communication between the UI and the host application.
 *
 * This module follows a layered architecture pattern:
 * - UI Layer: MynahUI component renders the chat interface
 * - Messaging Layer: Handles communication between UI and host application
 * - Event Handling Layer: Routes events to appropriate handlers
 */
const chat_client_ui_types_1 = require("@aws/chat-client-ui-types");
const language_server_runtimes_types_1 = require("@aws/language-server-runtimes-types");
const serverContracts_1 = require("../contracts/serverContracts");
const messager_1 = require("./messager");
const mynahUi_1 = require("./mynahUi");
const tabFactory_1 = require("./tabs/tabFactory");
const utils_1 = require("./utils");
const modelSelection_1 = require("./texts/modelSelection");
const getDefaultTabConfig = (agenticMode) => {
    return {
        tabTitle: 'Chat',
        promptInputInfo: 'Amazon Q Developer uses generative AI. You may need to verify responses. See the [AWS Responsible AI Policy](https://aws.amazon.com/machine-learning/responsible-ai/policy/).',
        promptInputPlaceholder: `Ask a question. Use${agenticMode ? ' @ to add context,' : ''} / for quick actions`,
    };
};
const createChat = (clientApi, config, chatClientAdapter, featureConfigSerialized) => {
    let mynahApi;
    const sendMessageToClient = (message) => {
        clientApi.postMessage(message);
    };
    const parseFeatureConfig = (featureConfigSerialized) => {
        try {
            const parsed = JSON.parse(featureConfigSerialized || '[]');
            return new Map(parsed);
        }
        catch (error) {
            console.error('Error parsing feature config:', featureConfigSerialized, error);
        }
        return new Map();
    };
    const featureConfig = parseFeatureConfig(featureConfigSerialized);
    /**
     * Handles incoming messages from the IDE or other sources.
     * Routes messages to appropriate handlers based on command type.
     *
     * 1. Messages with a 'sender' property are routed to the external connector
     *    if one is configured. This supports legacy systems and extensions.
     *
     * 2. Messages without a 'sender' property are processed by the standard
     *    command-based router, which dispatches based on the 'command' field.
     *
     * @param event - The message event containing data from the IDE
     */
    const handleInboundMessage = (event) => {
        if (event.data === undefined) {
            return;
        }
        const message = event.data;
        // 'message.sender' field is used by IDE connector logic to route messages through Chat Client to injected Connector.
        // When detected, chat client will delegate message handling back to IDE connectors.
        if (message?.sender && chatClientAdapter) {
            const connectorEvent = new MessageEvent('message', { data: JSON.stringify(message) });
            chatClientAdapter.handleMessageReceive(connectorEvent);
            return;
        }
        switch (message?.command) {
            case language_server_runtimes_types_1.CHAT_REQUEST_METHOD:
                mynahApi.addChatResponse(message.params, message.tabId, message.isPartialResult);
                break;
            case language_server_runtimes_types_1.CHAT_UPDATE_NOTIFICATION_METHOD: {
                const messageParams = message.params;
                if (messageParams?.tabId === 'mcpserver') {
                    mynahApi.mcpServerClick({ id: 'update-mcp-list' });
                    break;
                }
                else {
                    mynahApi.updateChat(message.params);
                    break;
                }
            }
            case language_server_runtimes_types_1.OPEN_TAB_REQUEST_METHOD:
                mynahApi.openTab(message.requestId, message.params);
                break;
            case chat_client_ui_types_1.SEND_TO_PROMPT:
                mynahApi.sendToPrompt(message.params);
                break;
            case chat_client_ui_types_1.GENERIC_COMMAND:
                mynahApi.sendGenericCommand(message.params);
                break;
            case chat_client_ui_types_1.ERROR_MESSAGE:
                mynahApi.showError(message.params);
                break;
            case language_server_runtimes_types_1.CONTEXT_COMMAND_NOTIFICATION_METHOD:
                mynahApi.sendContextCommands(message.params);
                break;
            case language_server_runtimes_types_1.PINNED_CONTEXT_NOTIFICATION_METHOD:
                mynahApi.sendPinnedContext(message.params);
                break;
            case language_server_runtimes_types_1.LIST_CONVERSATIONS_REQUEST_METHOD:
                mynahApi.listConversations(message.params);
                break;
            case language_server_runtimes_types_1.LIST_RULES_REQUEST_METHOD:
                mynahApi.listRules(message.params);
                break;
            case language_server_runtimes_types_1.RULE_CLICK_REQUEST_METHOD:
                mynahApi.ruleClicked(message.params);
                break;
            case language_server_runtimes_types_1.CONVERSATION_CLICK_REQUEST_METHOD:
                mynahApi.conversationClicked(message.params);
                break;
            case language_server_runtimes_types_1.LIST_MCP_SERVERS_REQUEST_METHOD:
                mynahApi.listMcpServers(message.params);
                break;
            case language_server_runtimes_types_1.MCP_SERVER_CLICK_REQUEST_METHOD:
                mynahApi.mcpServerClick(message.params);
                break;
            case language_server_runtimes_types_1.GET_SERIALIZED_CHAT_REQUEST_METHOD:
                mynahApi.getSerializedChat(message.requestId, message.params);
                break;
            case language_server_runtimes_types_1.CHAT_OPTIONS_UPDATE_NOTIFICATION_METHOD:
                if (message.params.modelId !== undefined || message.params.pairProgrammingMode !== undefined) {
                    const tabId = message.params.tabId;
                    const options = mynahUi.getTabData(tabId).getStore()?.promptInputOptions;
                    mynahUi.updateStore(tabId, {
                        promptInputOptions: options?.map(option => {
                            if (option.id === 'model-selection' && message.params.modelId !== undefined) {
                                return { ...option, value: message.params.modelId };
                            }
                            if (option.id === 'pair-programmer-mode' &&
                                message.params.pairProgrammingMode !== undefined) {
                                return { ...option, value: message.params.pairProgrammingMode ? 'true' : 'false' };
                            }
                            return option;
                        }),
                    });
                }
                else if (message.params.region) {
                    // get all tabs and update region
                    const allExistingTabs = mynahUi.getAllTabs();
                    for (const tabId in allExistingTabs) {
                        const options = mynahUi.getTabData(tabId).getStore()?.promptInputOptions;
                        mynahUi.updateStore(tabId, {
                            promptInputOptions: options?.map(option => option.id === 'model-selection'
                                ? modelSelection_1.modelSelectionForRegion[message.params.region]
                                : option),
                        });
                    }
                }
                else {
                    tabFactory.setInfoMessages(message.params.chatNotifications);
                }
                break;
            case chat_client_ui_types_1.CHAT_OPTIONS: {
                const params = message.params;
                if (params?.chatNotifications) {
                    tabFactory.setInfoMessages(message.params.chatNotifications);
                }
                if (params?.quickActions?.quickActionsCommandGroups) {
                    const quickActionCommandGroups = params.quickActions.quickActionsCommandGroups.map(group => ({
                        ...group,
                        commands: group.commands.map(command => ({
                            ...command,
                            icon: (0, utils_1.toMynahIcon)(command.icon),
                        })),
                    }));
                    tabFactory.updateQuickActionCommands(quickActionCommandGroups);
                }
                if (params?.mcpServers && config?.agenticMode) {
                    tabFactory.enableMcp();
                }
                if (params?.history) {
                    tabFactory.enableHistory();
                }
                if (params?.export) {
                    tabFactory.enableExport();
                }
                const allExistingTabs = mynahUi.getAllTabs();
                const highlightCommand = featureConfig.get('highlightCommand');
                if (tabFactory.initialTabId && allExistingTabs[tabFactory.initialTabId] && params?.chatNotifications) {
                    // Edge case: push banner message to initial tab when ChatOptions are received
                    // Because initial tab is added to MynahUi store at initialisation,
                    // that tab does not have banner message, which arrives in ChatOptions above.
                    const store = mynahUi.getTabData(tabFactory.initialTabId)?.getStore() || {};
                    const chatItems = store.chatItems || [];
                    const updatedInitialItems = tabFactory.getChatItems(false, false, chatItems);
                    // First clear the tab, so that messages are not appended https://github.com/aws/mynah-ui/blob/38608dff905b3790d85c73e2911ec7071c8a8cdf/docs/USAGE.md#using-updatestore-function
                    mynahUi.updateStore(tabFactory.initialTabId, {
                        chatItems: [],
                    });
                    mynahUi.updateStore(tabFactory.initialTabId, {
                        chatItems: updatedInitialItems,
                    });
                }
                for (const tabId in allExistingTabs) {
                    mynahUi.updateStore(tabId, {
                        ...tabFactory.getDefaultTabData(),
                        contextCommands: highlightCommand
                            ? [
                                {
                                    groupName: 'Additional Commands',
                                    commands: [(0, utils_1.toMynahContextCommand)(highlightCommand)],
                                },
                            ]
                            : [],
                    });
                }
                break;
            }
            default:
                // TODO: Report error?
                break;
        }
    };
    const chatApi = {
        sendChatPrompt: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.CHAT_REQUEST_METHOD, params });
        },
        sendQuickActionCommand: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.QUICK_ACTION_REQUEST_METHOD, params });
        },
        telemetry: (params) => {
            sendMessageToClient({ command: serverContracts_1.TELEMETRY, params });
        },
        tabAdded: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.TAB_ADD_NOTIFICATION_METHOD, params });
        },
        tabChanged: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.TAB_CHANGE_NOTIFICATION_METHOD, params });
        },
        tabRemoved: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.TAB_REMOVE_NOTIFICATION_METHOD, params });
        },
        insertToCursorPosition: (params) => {
            sendMessageToClient({ command: chat_client_ui_types_1.INSERT_TO_CURSOR_POSITION, params });
        },
        copyToClipboard: (params) => {
            sendMessageToClient({ command: chat_client_ui_types_1.COPY_TO_CLIPBOARD, params });
        },
        authFollowUpClicked: (params) => {
            sendMessageToClient({ command: chat_client_ui_types_1.AUTH_FOLLOW_UP_CLICKED, params });
        },
        followUpClicked: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.FOLLOW_UP_CLICK_NOTIFICATION_METHOD, params });
        },
        sendFeedback: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.FEEDBACK_NOTIFICATION_METHOD, params });
        },
        linkClick: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.LINK_CLICK_NOTIFICATION_METHOD, params });
        },
        sourceLinkClick: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.SOURCE_LINK_CLICK_NOTIFICATION_METHOD, params });
        },
        infoLinkClick: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.INFO_LINK_CLICK_NOTIFICATION_METHOD, params });
        },
        uiReady: () => {
            sendMessageToClient({
                command: language_server_runtimes_types_1.READY_NOTIFICATION_METHOD,
            });
            window.addEventListener('message', handleInboundMessage);
        },
        disclaimerAcknowledged: () => {
            sendMessageToClient({ command: chat_client_ui_types_1.DISCLAIMER_ACKNOWLEDGED });
        },
        chatPromptOptionAcknowledged: (messageId) => {
            sendMessageToClient({
                command: chat_client_ui_types_1.CHAT_PROMPT_OPTION_ACKNOWLEDGED,
                params: {
                    messageId,
                },
            });
        },
        onOpenTab: (requestId, params) => {
            if ('tabId' in params) {
                sendMessageToClient({
                    requestId: requestId,
                    command: language_server_runtimes_types_1.OPEN_TAB_REQUEST_METHOD,
                    params: {
                        success: true,
                        result: params,
                    },
                });
            }
            else {
                sendMessageToClient({
                    requestId: requestId,
                    command: language_server_runtimes_types_1.OPEN_TAB_REQUEST_METHOD,
                    params: {
                        success: false,
                        error: params,
                    },
                });
            }
        },
        createPrompt: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.CREATE_PROMPT_NOTIFICATION_METHOD, params });
        },
        fileClick: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.FILE_CLICK_NOTIFICATION_METHOD, params: params });
        },
        listConversations: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.LIST_CONVERSATIONS_REQUEST_METHOD, params });
        },
        conversationClick: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.CONVERSATION_CLICK_REQUEST_METHOD, params });
        },
        listMcpServers: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.LIST_MCP_SERVERS_REQUEST_METHOD, params });
        },
        mcpServerClick: function (params) {
            sendMessageToClient({ command: language_server_runtimes_types_1.MCP_SERVER_CLICK_REQUEST_METHOD, params });
        },
        tabBarAction: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.TAB_BAR_ACTION_REQUEST_METHOD, params });
        },
        onGetSerializedChat: (requestId, params) => {
            if ('content' in params) {
                sendMessageToClient({
                    requestId: requestId,
                    command: language_server_runtimes_types_1.GET_SERIALIZED_CHAT_REQUEST_METHOD,
                    params: {
                        success: true,
                        result: params,
                    },
                });
            }
            else {
                sendMessageToClient({
                    requestId: requestId,
                    command: language_server_runtimes_types_1.GET_SERIALIZED_CHAT_REQUEST_METHOD,
                    params: {
                        success: false,
                        error: params,
                    },
                });
            }
        },
        promptInputOptionChange: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.PROMPT_INPUT_OPTION_CHANGE_METHOD, params });
        },
        promptInputButtonClick: params => {
            // TODO
            sendMessageToClient({ command: language_server_runtimes_types_1.BUTTON_CLICK_REQUEST_METHOD, params });
        },
        stopChatResponse: (tabId) => {
            sendMessageToClient({ command: chat_client_ui_types_1.STOP_CHAT_RESPONSE, params: { tabId } });
        },
        sendButtonClickEvent: params => {
            sendMessageToClient({ command: language_server_runtimes_types_1.BUTTON_CLICK_REQUEST_METHOD, params: params });
        },
        onOpenSettings: (settingKey) => {
            sendMessageToClient({ command: chat_client_ui_types_1.OPEN_SETTINGS, params: { settingKey } });
        },
        onRuleClick: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.RULE_CLICK_REQUEST_METHOD, params });
        },
        listRules: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.LIST_RULES_REQUEST_METHOD, params });
        },
        onAddPinnedContext: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.PINNED_CONTEXT_ADD_NOTIFICATION_METHOD, params });
        },
        onRemovePinnedContext: (params) => {
            sendMessageToClient({ command: language_server_runtimes_types_1.PINNED_CONTEXT_REMOVE_NOTIFICATION_METHOD, params });
        },
    };
    const messager = new messager_1.Messager(chatApi);
    const tabFactory = new tabFactory_1.TabFactory(getDefaultTabConfig(config?.agenticMode), [
        ...(config?.quickActionCommands ? config.quickActionCommands : []),
    ]);
    if (config?.agenticMode) {
        tabFactory.enableAgenticMode();
    }
    if (config?.modelSelectionEnabled) {
        tabFactory.enableModelSelection();
    }
    const [mynahUi, api] = (0, mynahUi_1.createMynahUi)(messager, tabFactory, config?.disclaimerAcknowledged ?? false, config?.pairProgrammingAcknowledged ?? false, chatClientAdapter, featureConfig, !!config?.agenticMode);
    mynahApi = api;
    return mynahUi;
};
exports.createChat = createChat;
//# sourceMappingURL=chat.js.map