"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_HELP_PROMPT = exports.createMynahUi = exports.handleChatPrompt = exports.handlePromptInputChange = void 0;
/*!
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */
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 mynah_ui_1 = require("@aws/mynah-ui");
const tabFactory_1 = require("./tabs/tabFactory");
const disclaimer_1 = require("./texts/disclaimer");
const withAdapter_1 = require("./withAdapter");
const utils_1 = require("./utils");
const history_1 = require("./features/history");
const pairProgramming_1 = require("./texts/pairProgramming");
const ContextPrompt = {
    CreateItemId: 'create-saved-prompt',
    CancelButtonId: 'cancel-create-prompt',
    SubmitButtonId: 'submit-create-prompt',
    PromptNameFieldId: 'prompt-name',
};
const getTabPairProgrammingMode = (mynahUi, tabId) => {
    const promptInputOptions = mynahUi.getTabData(tabId)?.getStore()?.promptInputOptions ?? [];
    return promptInputOptions.find(item => item.id === 'pair-programmer-mode')?.value === 'true';
};
const handlePromptInputChange = (mynahUi, tabId, optionsValues) => {
    const promptTypeValue = optionsValues['pair-programmer-mode'];
    if (promptTypeValue != null) {
        mynahUi.addChatItem(tabId, promptTypeValue === 'true' ? pairProgramming_1.pairProgrammingModeOn : pairProgramming_1.pairProgrammingModeOff);
    }
};
exports.handlePromptInputChange = handlePromptInputChange;
const handleChatPrompt = (mynahUi, tabId, prompt, messager, triggerType, _eventId, agenticMode) => {
    let userPrompt = prompt.escapedPrompt;
    messager.onStopChatResponse(tabId);
    if (prompt.command) {
        // Temporary solution to handle clear quick actions on the client side
        if (prompt.command === '/clear') {
            mynahUi.updateStore(tabId, {
                chatItems: [],
            });
        }
        else if (prompt.command === '/help') {
            userPrompt = exports.DEFAULT_HELP_PROMPT;
        }
        // Send prompt when quick action command attached
        messager.onQuickActionCommand({
            quickAction: prompt.command,
            prompt: userPrompt,
            tabId,
        });
        if (prompt.command === '/clear') {
            return;
        }
    }
    else {
        // Send chat prompt to server
        const context = prompt.context?.map(c => (typeof c === 'string' ? { command: c } : c));
        messager.onChatPrompt({ prompt, tabId, context }, triggerType);
    }
    initializeChatResponse(mynahUi, tabId, userPrompt, agenticMode);
};
exports.handleChatPrompt = handleChatPrompt;
const initializeChatResponse = (mynahUi, tabId, userPrompt, agenticMode) => {
    mynahUi.addChatItem(tabId, {
        type: mynah_ui_1.ChatItemType.PROMPT,
        body: userPrompt,
    });
    // Set UI to loading state
    if (agenticMode) {
        mynahUi.updateStore(tabId, {
            loadingChat: true,
            cancelButtonWhenLoading: true,
            promptInputDisabledState: false,
        });
    }
    else {
        mynahUi.updateStore(tabId, {
            loadingChat: true,
            promptInputDisabledState: true,
        });
    }
    // Create initial empty response
    mynahUi.addChatItem(tabId, {
        type: mynah_ui_1.ChatItemType.ANSWER_STREAM,
    });
};
const createMynahUi = (messager, tabFactory, disclaimerAcknowledged, pairProgrammingCardAcknowledged, customChatClientAdapter, featureConfig, agenticMode) => {
    let disclaimerCardActive = !disclaimerAcknowledged;
    let programmingModeCardActive = !pairProgrammingCardAcknowledged;
    let contextCommandGroups;
    let chatEventHandlers = {
        onCodeInsertToCursorPosition(tabId, messageId, code, type, referenceTrackerInformation, eventId, codeBlockIndex, totalCodeBlocks) {
            const payload = {
                tabId,
                messageId,
                code,
                type,
                referenceTrackerInformation,
                eventId,
                codeBlockIndex,
                totalCodeBlocks,
            };
            messager.onInsertToCursorPosition(payload);
        },
        onFocusStateChanged(focusState) {
            messager.onFocusStateChanged(focusState);
        },
        onFollowUpClicked(tabId, messageId, followUp, eventId) {
            if (followUp.type !== undefined && (0, chat_client_ui_types_1.isValidAuthFollowUpType)(followUp.type)) {
                const payload = {
                    tabId,
                    messageId,
                    authFollowupType: followUp.type,
                };
                messager.onAuthFollowUpClicked(payload);
                mynahUi.updateStore(tabId, { promptInputDisabledState: false });
            }
            else {
                const prompt = followUp.prompt ? followUp.prompt : followUp.pillText;
                (0, exports.handleChatPrompt)(mynahUi, tabId, { prompt: prompt, escapedPrompt: prompt }, messager, 'click', eventId, agenticMode);
                const payload = {
                    tabId,
                    messageId,
                    followUp,
                };
                messager.onFollowUpClicked(payload);
            }
        },
        onChatPrompt(tabId, prompt, eventId) {
            (0, exports.handleChatPrompt)(mynahUi, tabId, prompt, messager, 'click', eventId, agenticMode);
        },
        onReady: () => {
            messager.onUiReady();
        },
        onFileClick: (tabId, filePath, deleted, messageId, eventId, fileDetails) => {
            messager.onFileClick({ tabId, filePath, messageId, fullPath: fileDetails?.data?.['fullPath'] });
        },
        onTabAdd: (tabId) => {
            const defaultTabBarData = tabFactory.getDefaultTabData();
            const defaultTabConfig = {
                quickActionCommands: defaultTabBarData.quickActionCommands,
                tabBarButtons: defaultTabBarData.tabBarButtons,
                contextCommands: [
                    ...(contextCommandGroups || []),
                    ...(featureConfig?.get('highlightCommand')
                        ? [
                            {
                                groupName: 'Additional commands',
                                commands: [(0, utils_1.toMynahContextCommand)(featureConfig.get('highlightCommand'))],
                            },
                        ]
                        : []),
                ],
                ...(disclaimerCardActive ? { promptInputStickyCard: disclaimer_1.disclaimerCard } : {}),
            };
            const tabStore = mynahUi.getTabData(tabId).getStore();
            // Tabs can be opened through different methods, including server-initiated 'openTab' requests.
            // The 'openTab' request is specifically used for loading historical chat sessions with pre-existing messages.
            // We check if tabMetadata.openTabKey exists - if it does and is set to true, we skip showing welcome messages
            // since this indicates we're loading a previous chat session rather than starting a new one.
            if (!tabStore?.tabMetadata || !tabStore.tabMetadata.openTabKey) {
                defaultTabConfig.chatItems = tabFactory.getChatItems(true, programmingModeCardActive, []);
            }
            mynahUi.updateStore(tabId, defaultTabConfig);
            messager.onTabAdd(tabId);
        },
        onTabRemove: (tabId) => {
            messager.onTabRemove(tabId);
        },
        onTabChange: (tabId) => {
            messager.onTabChange(tabId);
        },
        onResetStore: () => { },
        onCopyCodeToClipboard: (tabId, messageId, code, type, referenceTrackerInformation, eventId, codeBlockIndex, totalCodeBlocks) => {
            const payload = {
                tabId,
                messageId,
                code,
                type,
                referenceTrackerInformation,
                eventId,
                codeBlockIndex,
                totalCodeBlocks,
            };
            messager.onCopyCodeToClipboard(payload);
        },
        onVote: (tabId, messageId, vote, eventId) => {
            const payload = {
                tabId,
                messageId,
                vote,
                eventId,
            };
            messager.onVote(payload);
        },
        onSendFeedback: (tabId, feedbackPayload, eventId) => {
            const payload = {
                tabId,
                feedbackPayload,
                eventId,
            };
            messager.onSendFeedback(payload);
            mynahUi.notify({
                type: mynah_ui_1.NotificationType.INFO,
                title: 'Your feedback is sent',
                content: 'Thanks for your feedback.',
            });
        },
        onLinkClick: (tabId, messageId, link, mouseEvent, eventId) => {
            mouseEvent?.preventDefault();
            mouseEvent?.stopPropagation();
            mouseEvent?.stopImmediatePropagation();
            const payload = {
                tabId,
                messageId,
                link,
                eventId,
            };
            messager.onLinkClick(payload);
        },
        onSourceLinkClick: (tabId, messageId, link, mouseEvent, eventId) => {
            mouseEvent?.preventDefault();
            mouseEvent?.stopPropagation();
            mouseEvent?.stopImmediatePropagation();
            const payload = {
                tabId,
                messageId,
                link,
                eventId,
            };
            messager.onSourceLinkClick(payload);
        },
        onInfoLinkClick: (tabId, link, mouseEvent, eventId) => {
            mouseEvent?.preventDefault();
            mouseEvent?.stopPropagation();
            mouseEvent?.stopImmediatePropagation();
            const payload = {
                tabId,
                link,
                eventId,
            };
            messager.onInfoLinkClick(payload);
        },
        onInBodyButtonClicked: (tabId, messageId, action, eventId) => {
            if (action.id === disclaimer_1.disclaimerAcknowledgeButtonId) {
                // Hide the legal disclaimer card
                disclaimerCardActive = false;
                // Update the disclaimer getting acknowledged
                messager.onDisclaimerAcknowledged();
                // Remove all disclaimer cards from all tabs
                Object.keys(mynahUi.getAllTabs()).forEach(storeTabKey => {
                    mynahUi.updateStore(storeTabKey, { promptInputStickyCard: null });
                });
            }
            else if (action.id === language_server_runtimes_types_1.OPEN_WORKSPACE_INDEX_SETTINGS_BUTTON_ID) {
                messager.onOpenSettings('amazonQ.workspaceIndex');
            }
            else {
                const payload = {
                    tabId,
                    messageId,
                    buttonId: action.id,
                };
                messager.onButtonClick(payload);
            }
            if (action.id === 'stop-shell-command') {
                messager.onStopChatResponse(tabId);
            }
        },
        onContextSelected: (contextItem, tabId) => {
            if (contextItem.id === ContextPrompt.CreateItemId) {
                mynahUi.showCustomForm(tabId, [
                    {
                        id: ContextPrompt.PromptNameFieldId,
                        type: 'textinput',
                        mandatory: true,
                        autoFocus: true,
                        title: 'Prompt name',
                        placeholder: 'Enter prompt name',
                        validationPatterns: {
                            patterns: [
                                {
                                    pattern: /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,99}$/,
                                    errorMessage: 'Use only letters, numbers, hyphens, and underscores, starting with a letter or number. Maximum 100 characters.',
                                },
                            ],
                        },
                        description: "Use this prompt by typing '@' followed by the prompt name.",
                    },
                ], [
                    {
                        id: ContextPrompt.CancelButtonId,
                        text: 'Cancel',
                        status: 'clear',
                        waitMandatoryFormItems: false,
                    },
                    {
                        id: ContextPrompt.SubmitButtonId,
                        text: 'Create',
                        status: 'main',
                        waitMandatoryFormItems: true,
                    },
                ], `Create a saved prompt`);
                return false;
            }
            return true;
        },
        onCustomFormAction: (tabId, action) => {
            if (action.id === ContextPrompt.SubmitButtonId) {
                messager.onCreatePrompt(action.formItemValues[ContextPrompt.PromptNameFieldId]);
            }
        },
        onFormTextualItemKeyPress: (event, formData, itemId) => {
            if (itemId === ContextPrompt.PromptNameFieldId && event.key === 'Enter') {
                event.preventDefault();
                messager.onCreatePrompt(formData[ContextPrompt.PromptNameFieldId]);
                return true;
            }
            return false;
        },
        onTabBarButtonClick: (tabId, buttonId) => {
            if (buttonId === history_1.ChatHistory.TabBarButtonId) {
                messager.onListConversations();
                return;
            }
            if (buttonId === tabFactory_1.ExportTabBarButtonId) {
                messager.onTabBarAction({
                    tabId,
                    action: 'export',
                });
                return;
            }
            throw new Error(`Unhandled tab bar button id: ${buttonId}`);
        },
        onPromptInputOptionChange: (tabId, optionsValues) => {
            if (agenticMode) {
                (0, exports.handlePromptInputChange)(mynahUi, tabId, optionsValues);
            }
            messager.onPromptInputOptionChange({ tabId, optionsValues });
        },
        onMessageDismiss: (tabId, messageId) => {
            if (messageId === pairProgramming_1.programmerModeCard.messageId) {
                programmingModeCardActive = false;
                messager.onChatPromptOptionAcknowledged(messageId);
                // Update the tab defaults to hide the programmer mode card for new tabs
                mynahUi.updateTabDefaults({
                    store: {
                        chatItems: tabFactory.getChatItems(true, false),
                    },
                });
            }
        },
        onStopChatResponse: tabId => {
            messager.onStopChatResponse(tabId);
        },
    };
    const mynahUiProps = {
        tabs: {},
        defaults: {
            store: tabFactory.createTab(false),
        },
        config: {
            maxTabs: 10,
            texts: {
                ...uiComponentsTexts,
                // Fallback to original texts in non-agentic chat mode
                stopGenerating: agenticMode ? uiComponentsTexts.stopGenerating : 'Stop generating',
                spinnerText: agenticMode ? uiComponentsTexts.spinnerText : 'Generating your answer...',
            },
            // RTS max user input is 600k, we need to leave around 500 chars to user to type the question
            // beside, MynahUI will automatically crop it depending on the available chars left from the prompt field itself by using a 96 chars of threshold
            // if we want to max user input as 599500, need to configure the maxUserInput as 599596
            maxUserInput: 599596,
            userInputLengthWarningThreshold: 550000,
        },
    };
    const mynahUiRef = { mynahUI: undefined };
    if (customChatClientAdapter) {
        // Attach routing to custom adapter top of default message handlers
        chatEventHandlers = (0, withAdapter_1.withAdapter)(chatEventHandlers, mynahUiRef, customChatClientAdapter);
    }
    const mynahUi = new mynah_ui_1.MynahUI({
        ...mynahUiProps,
        ...chatEventHandlers,
    });
    mynahUiRef.mynahUI = mynahUi;
    const getTabStore = (tabId = mynahUi.getSelectedTabId()) => {
        return tabId ? mynahUi.getAllTabs()[tabId]?.store : undefined;
    };
    // The 'openTab' parameter indicates whether this tab creation is initiated by 'openTab' server request
    // to restore a previous chat session (true) or if it's a new client-side tab creation (false/undefined).
    // This distinction helps maintain consistent tab behavior between fresh conversations and restored sessions.
    const createTabId = (openTab) => {
        const tabId = mynahUi.updateStore('', {
            ...tabFactory.createTab(disclaimerCardActive),
            tabMetadata: { openTabKey: openTab ? true : false },
        });
        if (tabId === undefined) {
            mynahUi.notify({
                content: uiComponentsTexts.noMoreTabsTooltip,
                type: mynah_ui_1.NotificationType.WARNING,
            });
            return undefined;
        }
        return tabId;
    };
    const getOrCreateTabId = () => {
        const tabId = mynahUi.getSelectedTabId();
        return tabId ?? createTabId();
    };
    const contextListToHeader = (contextList) => {
        if (contextList === undefined) {
            return undefined;
        }
        return {
            fileList: {
                fileTreeTitle: '',
                filePaths: contextList.filePaths?.map(file => file),
                rootFolderTitle: contextList.rootFolderTitle ?? 'Context',
                flatList: true,
                collapsed: true,
                hideFileCount: true,
                details: Object.fromEntries(Object.entries(contextList.details || {}).map(([filePath, fileDetails]) => [
                    filePath,
                    {
                        label: fileDetails.lineRanges
                            ?.map(range => range.first === -1 || range.second === -1
                            ? ''
                            : `line ${range.first} - ${range.second}`)
                            .join(', ') || '',
                        description: fileDetails.description,
                        clickable: true,
                        data: {
                            fullPath: fileDetails.fullPath || '',
                        },
                    },
                ])),
            },
        };
    };
    const addChatResponse = (chatResult, tabId, isPartialResult) => {
        if (agenticMode) {
            agenticAddChatResponse(chatResult, tabId, isPartialResult);
        }
        else {
            legacyAddChatResponse(chatResult, tabId, isPartialResult);
        }
    };
    // addChatResponse handler to support Agentic chat UX changes for handling responses streaming.
    const agenticAddChatResponse = (chatResult, tabId, isPartialResult) => {
        const { type, ...chatResultWithoutType } = chatResult;
        let header = (0, utils_1.toMynahHeader)(chatResult.header);
        const fileList = (0, utils_1.toMynahFileList)(chatResult.fileList);
        const buttons = (0, utils_1.toMynahButtons)(chatResult.buttons);
        if (chatResult.contextList !== undefined) {
            header = contextListToHeader(chatResult.contextList);
        }
        const store = mynahUi.getTabData(tabId)?.getStore() || {};
        const chatItems = store.chatItems || [];
        const isPairProgrammingMode = getTabPairProgrammingMode(mynahUi, tabId);
        if (chatResult.additionalMessages?.length) {
            mynahUi.updateStore(tabId, {
                loadingChat: true,
                cancelButtonWhenLoading: true,
            });
            chatResult.additionalMessages.forEach(am => {
                const chatItem = {
                    messageId: am.messageId,
                    type: am.type === 'tool'
                        ? mynah_ui_1.ChatItemType.ANSWER
                        : am.type === 'directive'
                            ? mynah_ui_1.ChatItemType.DIRECTIVE
                            : mynah_ui_1.ChatItemType.ANSWER_STREAM,
                    ...prepareChatItemFromMessage(am, isPairProgrammingMode, isPartialResult),
                };
                if (!chatItems.find(ci => ci.messageId === am.messageId)) {
                    mynahUi.addChatItem(tabId, chatItem);
                }
                else {
                    mynahUi.updateChatAnswerWithMessageId(tabId, am.messageId, chatItem);
                }
            });
        }
        if (isPartialResult) {
            mynahUi.updateStore(tabId, {
                loadingChat: true,
                cancelButtonWhenLoading: true,
            });
            const chatItem = {
                ...chatResult,
                body: chatResult.body,
                type: mynah_ui_1.ChatItemType.ANSWER_STREAM,
                header: header,
                buttons: buttons,
                fileList,
                codeBlockActions: isPairProgrammingMode ? { 'insert-to-cursor': null } : undefined,
            };
            if (!chatItems.find(ci => ci.messageId === chatResult.messageId)) {
                mynahUi.addChatItem(tabId, chatItem);
            }
            else {
                mynahUi.updateChatAnswerWithMessageId(tabId, chatResult.messageId, chatItem);
            }
            return;
        }
        // If chat response from server is an empty object don't do anything
        if (Object.keys(chatResult).length === 0) {
            return;
        }
        // If the response is auth follow-up show it as a system prompt
        const followUpOptions = chatResult.followUp?.options;
        const isValidAuthFollowUp = followUpOptions &&
            followUpOptions.length > 0 &&
            followUpOptions[0].type &&
            (0, chat_client_ui_types_1.isValidAuthFollowUpType)(followUpOptions[0].type);
        if (chatResult.body === '' && isValidAuthFollowUp) {
            mynahUi.addChatItem(tabId, {
                type: mynah_ui_1.ChatItemType.SYSTEM_PROMPT,
                ...chatResultWithoutType, // type for MynahUI differs from ChatResult types so we ignore it
                header: header,
                buttons: buttons,
            });
            // TODO, prompt should be disabled until user is authenticated
            // Currently we don't have a mechanism to notify chat-client about auth changes
            // mynahUi.updateStore(tabId, { promptInputDisabledState: true })
            return;
        }
        const followUps = chatResult.followUp
            ? {
                text: chatResult.followUp.text ?? 'Suggested follow up questions:',
                options: chatResult.followUp.options,
            }
            : {};
        const chatItem = {
            ...chatResult,
            body: chatResult.body,
            type: mynah_ui_1.ChatItemType.ANSWER_STREAM,
            header: header,
            buttons: buttons,
            codeBlockActions: isPairProgrammingMode ? { 'insert-to-cursor': null } : undefined,
        };
        if (!chatItems.find(ci => ci.messageId === chatResult.messageId)) {
            mynahUi.addChatItem(tabId, chatItem);
        }
        mynahUi.endMessageStream(tabId, chatResult.messageId ?? '', {
            header: header,
            buttons: buttons,
            body: chatResult.body,
            followUp: followUps,
            relatedContent: chatResult.relatedContent,
            canBeVoted: chatResult.canBeVoted,
            codeReference: chatResult.codeReference,
            fileList: chatResult.fileList,
            // messageId excluded
        });
        mynahUi.updateStore(tabId, {
            loadingChat: false,
            cancelButtonWhenLoading: true,
            promptInputDisabledState: false,
        });
    };
    // addChatResponse handler to support extensions that haven't migrated to agentic chat yet
    const legacyAddChatResponse = (chatResult, tabId, isPartialResult) => {
        const { type, ...chatResultWithoutType } = chatResult;
        let header = undefined;
        if (chatResult.contextList !== undefined) {
            header = {
                fileList: {
                    fileTreeTitle: '',
                    filePaths: chatResult.contextList.filePaths?.map(file => file),
                    rootFolderTitle: 'Context',
                    flatList: true,
                    collapsed: true,
                    hideFileCount: true,
                    details: Object.fromEntries(Object.entries(chatResult.contextList.details || {}).map(([filePath, fileDetails]) => [
                        filePath,
                        {
                            label: fileDetails.lineRanges
                                ?.map(range => range.first === -1 || range.second === -1
                                ? ''
                                : `line ${range.first} - ${range.second}`)
                                .join(', ') || '',
                            description: filePath,
                            clickable: true,
                        },
                    ])),
                },
            };
        }
        if (isPartialResult) {
            // @ts-ignore - type for MynahUI differs from ChatResult types so we ignore it
            mynahUi.updateLastChatAnswer(tabId, { ...chatResultWithoutType, header: header });
            return;
        }
        // If chat response from server is an empty object don't do anything
        if (Object.keys(chatResult).length === 0) {
            return;
        }
        // If the response is auth follow-up show it as a system prompt
        const followUpOptions = chatResult.followUp?.options;
        const isValidAuthFollowUp = followUpOptions &&
            followUpOptions.length > 0 &&
            followUpOptions[0].type &&
            (0, chat_client_ui_types_1.isValidAuthFollowUpType)(followUpOptions[0].type);
        if (chatResult.body === '' && isValidAuthFollowUp) {
            // @ts-ignore - type for MynahUI differs from ChatResult types so we ignore it
            mynahUi.addChatItem(tabId, {
                type: mynah_ui_1.ChatItemType.SYSTEM_PROMPT,
                ...chatResultWithoutType,
            });
            // TODO, prompt should be disabled until user is authenticated
            // Currently we don't have a mechanism to notify chat-client about auth changes
            // mynahUi.updateStore(tabId, { promptInputDisabledState: true })
            return;
        }
        const followUps = chatResult.followUp
            ? {
                text: chatResult.followUp.text ?? 'Suggested follow up questions:',
                options: chatResult.followUp.options,
            }
            : {};
        mynahUi.updateLastChatAnswer(tabId, {
            header: header,
            body: chatResult.body,
            messageId: chatResult.messageId,
            followUp: followUps,
            relatedContent: chatResult.relatedContent,
            canBeVoted: chatResult.canBeVoted,
        });
        mynahUi.endMessageStream(tabId, chatResult.messageId ?? '');
        mynahUi.updateStore(tabId, {
            loadingChat: false,
            promptInputDisabledState: false,
        });
    };
    const updateChat = (params) => {
        const isChatLoading = params.state?.inProgress;
        mynahUi.updateStore(params.tabId, {
            loadingChat: isChatLoading,
            cancelButtonWhenLoading: agenticMode,
        });
        if (params.data?.messages.length) {
            const { tabId } = params;
            const store = mynahUi.getTabData(tabId).getStore() || {};
            const chatItems = store.chatItems || [];
            params.data?.messages.forEach(updatedMessage => {
                if (!updatedMessage.messageId) {
                    // Do not process messages without known ID.
                    return;
                }
                const oldMessage = chatItems.find(ci => ci.messageId === updatedMessage.messageId);
                if (!oldMessage)
                    return;
                const chatItem = {
                    type: oldMessage.type,
                    ...prepareChatItemFromMessage(updatedMessage, getTabPairProgrammingMode(mynahUi, tabId)),
                };
                mynahUi.updateChatAnswerWithMessageId(tabId, updatedMessage.messageId, chatItem);
            });
        }
    };
    const updateFinalItemTypes = (tabId) => {
        const store = mynahUi.getTabData(tabId)?.getStore() || {};
        const chatItems = store.chatItems || [];
        const updatedItems = chatItems.map(item => ({
            ...item,
            type: item.type === mynah_ui_1.ChatItemType.ANSWER_STREAM && !item.body ? mynah_ui_1.ChatItemType.ANSWER : item.type,
        }));
        mynahUi.updateStore(tabId, {
            loadingChat: false,
            cancelButtonWhenLoading: agenticMode,
            chatItems: updatedItems,
            promptInputDisabledState: false,
        });
    };
    const prepareChatItemFromMessage = (message, isPairProgrammingMode, isPartialResult) => {
        const contextHeader = contextListToHeader(message.contextList);
        const header = contextHeader || (0, utils_1.toMynahHeader)(message.header); // Is this mutually exclusive?
        const fileList = (0, utils_1.toMynahFileList)(message.fileList);
        let processedHeader = header;
        if (message.type === 'tool') {
            processedHeader = { ...header };
            if (header?.buttons) {
                processedHeader.buttons = header.buttons.map(button => ({
                    ...button,
                    status: button.status ?? 'clear',
                }));
            }
            if (header?.fileList) {
                processedHeader.fileList = {
                    ...header.fileList,
                    fileTreeTitle: '',
                    hideFileCount: true,
                    details: (0, utils_1.toDetailsWithoutIcon)(header.fileList.details),
                };
            }
            if (!isPartialResult) {
                if (processedHeader) {
                    processedHeader.status = undefined;
                }
            }
        }
        // Check if header should be included
        const includeHeader = processedHeader &&
            ((processedHeader.buttons !== undefined &&
                processedHeader.buttons !== null &&
                processedHeader.buttons.length > 0) ||
                processedHeader.status !== undefined ||
                processedHeader.icon !== undefined);
        const padding = message.type === 'tool' ? (fileList ? true : message.messageId?.endsWith('_permission')) : undefined;
        const processedButtons = (0, utils_1.toMynahButtons)(message.buttons)?.map(button => button.id === 'undo-all-changes' ? { ...button, position: 'outside' } : button);
        // Adding this conditional check to show the stop message in the center.
        const contentHorizontalAlignment = message.type === 'directive' && message.messageId?.startsWith('stopped') ? 'center' : undefined;
        const shouldMute = message.header?.status?.text === 'Stopped' || message.header?.status?.text === 'Rejected';
        return {
            body: message.body,
            header: includeHeader ? processedHeader : undefined,
            buttons: processedButtons,
            fileList,
            // file diffs in the header need space
            fullWidth: message.type === 'tool' && message.header?.buttons ? true : undefined,
            padding,
            contentHorizontalAlignment,
            wrapCodes: message.type === 'tool',
            codeBlockActions: message.type === 'tool'
                ? { 'insert-to-cursor': null, copy: null }
                : isPairProgrammingMode
                    ? { 'insert-to-cursor': null }
                    : undefined,
            ...(shouldMute ? { muted: true } : {}),
        };
    };
    const sendToPrompt = (params) => {
        const tabId = getOrCreateTabId();
        if (!tabId)
            return;
        if (params.autoSubmit && params.prompt) {
            messager.onChatPrompt({ prompt: params.prompt, tabId, context: undefined }, 'contextMenu');
            initializeChatResponse(mynahUi, tabId, params.prompt.prompt, agenticMode);
        }
        else {
            mynahUi.addToUserPrompt(tabId, params.selection, 'code');
        }
        messager.onSendToPrompt(params, tabId);
    };
    const sendGenericCommand = (params) => {
        let tabId = getOrCreateTabId();
        if (!tabId)
            return;
        // send to a new tab if the current tab is loading
        if (getTabStore(tabId)?.loadingChat) {
            tabId = createTabId();
            if (!tabId)
                return;
        }
        const body = [
            params.genericCommand,
            ' the following part of my code:',
            '\n~~~~\n',
            params.selection,
            '\n~~~~\n',
        ].join('');
        const chatPrompt = { prompt: body, escapedPrompt: body };
        (0, exports.handleChatPrompt)(mynahUi, tabId, chatPrompt, messager, params.triggerType, undefined, agenticMode);
    };
    const showError = (params) => {
        const tabId = getOrCreateTabId();
        if (!tabId)
            return;
        const answer = {
            type: mynah_ui_1.ChatItemType.ANSWER,
            body: `**${params.title}** 
${params.message}`,
        };
        mynahUi.updateStore(tabId, {
            loadingChat: false,
            cancelButtonWhenLoading: agenticMode,
            promptInputDisabledState: false,
        });
        mynahUi.addChatItem(params.tabId, answer);
        messager.onError(params);
    };
    const openTab = (requestId, params) => {
        if (params.tabId) {
            if (params.tabId !== mynahUi.getSelectedTabId()) {
                mynahUi.selectTab(params.tabId);
            }
            messager.onOpenTab(requestId, { tabId: params.tabId });
        }
        else {
            const messages = params.newTabOptions?.data?.messages;
            const tabId = createTabId(true);
            if (tabId) {
                mynahUi.updateStore(tabId, {
                    chatItems: tabFactory.getChatItems(messages ? false : true, programmingModeCardActive, messages),
                });
                messager.onOpenTab(requestId, { tabId });
            }
            else {
                messager.onOpenTab(requestId, {
                    type: 'InvalidRequest',
                    message: 'No more tabs available',
                });
            }
        }
    };
    const toContextCommands = (commands) => {
        return commands.map(command => ({
            ...command,
            children: command.children?.map(child => ({
                ...child,
                commands: toContextCommands(child.commands),
            })),
            icon: (0, utils_1.toMynahIcon)(command.icon),
        }));
    };
    const sendContextCommands = (params) => {
        contextCommandGroups = params.contextCommandGroups.map(group => ({
            ...group,
            commands: toContextCommands(group.commands),
        }));
        Object.keys(mynahUi.getAllTabs()).forEach(tabId => {
            mynahUi.updateStore(tabId, {
                contextCommands: [
                    ...(contextCommandGroups || []),
                    ...(featureConfig?.get('highlightCommand')
                        ? [
                            {
                                groupName: 'Additional commands',
                                commands: [(0, utils_1.toMynahContextCommand)(featureConfig.get('highlightCommand'))],
                            },
                        ]
                        : []),
                ],
            });
        });
    };
    const chatHistoryList = new history_1.ChatHistoryList(mynahUi, messager);
    const listConversations = (params) => {
        chatHistoryList.show(params);
    };
    const conversationClicked = (params) => {
        if (!params.success) {
            mynahUi.notify({
                content: `Failed to ${params.action ?? 'open'} the history`,
                type: mynah_ui_1.NotificationType.ERROR,
            });
            return;
        }
        // close history list if conversation item was successfully opened
        if (!params.action) {
            chatHistoryList.close();
            return;
        }
        // request update conversations list if conversation item was successfully deleted
        if (params.action === 'delete') {
            messager.onListConversations();
        }
    };
    const getSerializedChat = (requestId, params) => {
        const supportedFormats = ['markdown', 'html'];
        if (!supportedFormats.includes(params.format)) {
            mynahUi.notify({
                content: `Failed to export chat`,
                type: mynah_ui_1.NotificationType.ERROR,
            });
            messager.onGetSerializedChat(requestId, {
                type: 'InvalidRequest',
                message: `Failed to get serialized chat content, ${params.format} is not supported`,
            });
            return;
        }
        try {
            const serializedChat = mynahUi.serializeChat(params.tabId, params.format);
            messager.onGetSerializedChat(requestId, {
                content: serializedChat,
            });
        }
        catch (err) {
            messager.onGetSerializedChat(requestId, {
                type: 'InternalError',
                message: 'Failed to get serialized chat content',
            });
        }
    };
    const api = {
        addChatResponse: addChatResponse,
        updateChat: updateChat,
        sendToPrompt: sendToPrompt,
        sendGenericCommand: sendGenericCommand,
        showError: showError,
        openTab: openTab,
        sendContextCommands: sendContextCommands,
        listConversations: listConversations,
        conversationClicked: conversationClicked,
        getSerializedChat: getSerializedChat,
        createTabId: createTabId,
    };
    return [mynahUi, api];
};
exports.createMynahUi = createMynahUi;
exports.DEFAULT_HELP_PROMPT = 'What can Amazon Q help me with?';
const uiComponentsTexts = {
    mainTitle: 'Amazon Q (Preview)',
    copy: 'Copy',
    insertAtCursorLabel: 'Insert at cursor',
    feedbackFormTitle: 'Report an issue',
    feedbackFormOptionsLabel: 'What type of issue would you like to report?',
    feedbackFormCommentLabel: 'Description of issue (optional):',
    feedbackThanks: 'Thanks for your feedback!',
    feedbackReportButtonLabel: 'Report an issue',
    codeSuggestions: 'Code suggestions',
    files: 'file(s)',
    clickFileToViewDiff: 'Click on a file to view diff.',
    showMore: 'Show more',
    save: 'Save',
    cancel: 'Cancel',
    submit: 'Submit',
    stopGenerating: 'Stop',
    copyToClipboard: 'Copied to clipboard',
    noMoreTabsTooltip: 'You can only open ten conversation tabs at a time.',
    codeSuggestionWithReferenceTitle: 'Some suggestions contain code with references.',
    spinnerText: 'Thinking...',
};
//# sourceMappingURL=mynahUi.js.map