"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const jsDomInjector_1 = require("../test/jsDomInjector");
// This needs to be run before all other imports so that mynah ui gets loaded inside of jsdom
(0, jsDomInjector_1.injectJSDOM)();
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 mocha_1 = require("mocha");
const sinon_1 = require("sinon");
const chat_1 = require("./chat");
const sinon = require("sinon");
const serverContracts_1 = require("../contracts/serverContracts");
const telemetry_1 = require("../contracts/telemetry");
const tabFactory_1 = require("./tabs/tabFactory");
describe('Chat', () => {
    const sandbox = sinon.createSandbox();
    const initialTabId = 'tab-1';
    let mynahUi;
    let clientApi;
    before(() => {
        // Mock global observers for test environment
        // @ts-ignore
        global.ResizeObserver = null;
        // @ts-ignore
        global.IntersectionObserver = null;
    });
    beforeEach(() => {
        sandbox.stub(tabFactory_1.TabFactory, 'generateUniqueId').returns(initialTabId);
        sandbox.stub(tabFactory_1.TabFactory.prototype, 'enableHistory');
        sandbox.stub(tabFactory_1.TabFactory.prototype, 'enableExport');
        clientApi = {
            postMessage: sandbox.stub(),
        };
        mynahUi = (0, chat_1.createChat)(clientApi, {
            agenticMode: true,
        });
    });
    (0, mocha_1.afterEach)(() => {
        sandbox.restore();
        Object.keys(mynahUi.getAllTabs()).forEach(tabId => {
            mynahUi.removeTab(tabId, mynahUi.lastEventId);
        });
    });
    after(() => {
        // @ts-ignore
        global.ResizeObserver = undefined;
    });
    it('publishes ready event when initialized', () => {
        sinon_1.assert.calledWithExactly(clientApi.postMessage.firstCall, { command: language_server_runtimes_types_1.READY_NOTIFICATION_METHOD });
    });
    it('creates initial tab when chat options are provided', () => {
        const bannerText = 'This is a test banner message';
        const eventParams = {
            command: chat_client_ui_types_1.CHAT_OPTIONS,
            params: {
                chatNotifications: {
                    bannerText: bannerText,
                },
            },
        };
        const sendToPromptEvent = createInboundEvent(eventParams);
        window.dispatchEvent(sendToPromptEvent);
        sinon_1.assert.calledWithExactly(clientApi.postMessage.firstCall, { command: language_server_runtimes_types_1.READY_NOTIFICATION_METHOD });
        sinon_1.assert.calledWithExactly(clientApi.postMessage.secondCall, {
            command: serverContracts_1.TELEMETRY,
            params: { name: telemetry_1.ENTER_FOCUS },
        });
        sinon_1.assert.calledWithExactly(clientApi.postMessage.thirdCall, {
            command: language_server_runtimes_types_1.TAB_ADD_NOTIFICATION_METHOD,
            params: { tabId: sinon.match.string },
        });
        sinon_1.assert.calledWithExactly(clientApi.postMessage.lastCall, {
            command: serverContracts_1.TELEMETRY,
            params: {
                triggerType: 'click',
                name: telemetry_1.TAB_ADD_TELEMETRY_EVENT,
                tabId: sinon.match.string,
            },
        });
    });
    it('publishes telemetry event, when send to prompt is triggered', () => {
        const eventParams = { command: chat_client_ui_types_1.SEND_TO_PROMPT, params: { prompt: 'hey' } };
        const sendToPromptEvent = createInboundEvent(eventParams);
        window.dispatchEvent(sendToPromptEvent);
        sinon_1.assert.calledWithExactly(clientApi.postMessage, {
            command: serverContracts_1.TELEMETRY,
            params: {
                name: telemetry_1.SEND_TO_PROMPT_TELEMETRY_EVENT,
                tabId: mynahUi.getSelectedTabId(),
                ...eventParams.params,
            },
        });
    });
    it('publishes telemetry event, when show error is triggered', () => {
        const eventParams = { command: chat_client_ui_types_1.ERROR_MESSAGE, params: { tabId: '123' } };
        const errorEvent = createInboundEvent(eventParams);
        window.dispatchEvent(errorEvent);
        sinon_1.assert.calledWithExactly(clientApi.postMessage, {
            command: serverContracts_1.TELEMETRY,
            params: {
                name: telemetry_1.ERROR_MESSAGE_TELEMETRY_EVENT,
                ...eventParams.params,
            },
        });
    });
    it('publishes tab added event, when UI tab is added', () => {
        const tabId = mynahUi.updateStore('', {});
        sinon_1.assert.calledWithMatch(clientApi.postMessage, {
            command: language_server_runtimes_types_1.TAB_ADD_NOTIFICATION_METHOD,
            params: { tabId: tabId },
        });
    });
    it('publishes tab removed event, when UI tab is removed', () => {
        const tabId = mynahUi.updateStore('', {});
        mynahUi.removeTab(tabId, mynahUi.lastEventId);
        sinon_1.assert.calledWithMatch(clientApi.postMessage, {
            command: language_server_runtimes_types_1.TAB_REMOVE_NOTIFICATION_METHOD,
            params: { tabId: tabId },
        });
    });
    it('publishes tab changed event, when UI tab is changed', () => {
        const tabId = mynahUi.updateStore('', {});
        mynahUi.updateStore('', {});
        clientApi.postMessage.resetHistory();
        mynahUi.selectTab(tabId, mynahUi.lastEventId);
        sinon_1.assert.calledOnceWithExactly(clientApi.postMessage, {
            command: language_server_runtimes_types_1.TAB_CHANGE_NOTIFICATION_METHOD,
            params: { tabId: tabId },
        });
    });
    it('generic command creates a chat request', () => {
        const genericCommand = 'Fix';
        const selection = 'some code';
        const tabId = '123';
        const triggerType = 'click';
        const expectedPrompt = `${genericCommand} the following part of my code:\n~~~~\n${selection}\n~~~~\n`;
        const genericCommandEvent = createInboundEvent({
            command: chat_client_ui_types_1.GENERIC_COMMAND,
            params: { tabId, selection, triggerType, genericCommand },
        });
        window.dispatchEvent(genericCommandEvent);
        sinon_1.assert.calledWithMatch(clientApi.postMessage, {
            command: language_server_runtimes_types_1.CHAT_REQUEST_METHOD,
            params: {
                prompt: {
                    prompt: expectedPrompt,
                    escapedPrompt: expectedPrompt,
                },
            },
        });
    });
    it('open tab requestId was propagated from inbound to outbound message', () => {
        const requestId = 'request-1234';
        const openTabEvent = createInboundEvent({
            command: language_server_runtimes_types_1.OPEN_TAB_REQUEST_METHOD,
            params: {
                newTabOptions: {
                    data: {
                        messages: [],
                    },
                },
            },
            requestId: requestId,
        });
        window.dispatchEvent(openTabEvent);
        // Verify that postMessage was called with the correct requestId
        sinon_1.assert.calledWithExactly(clientApi.postMessage, {
            command: language_server_runtimes_types_1.OPEN_TAB_REQUEST_METHOD,
            requestId,
            params: {
                success: true,
                result: sinon.match({
                    tabId: sinon.match.string,
                }),
            },
        });
    });
    it('complete chat response triggers ui events', () => {
        const endMessageStreamStub = sandbox.stub(mynahUi, 'endMessageStream');
        const updateStoreStub = sandbox.stub(mynahUi, 'updateStore');
        const tabId = '123';
        const body = 'some response';
        const chatEvent = createInboundEvent({
            command: language_server_runtimes_types_1.CHAT_REQUEST_METHOD,
            tabId,
            params: { body },
        });
        window.dispatchEvent(chatEvent);
        sinon_1.assert.calledOnceWithExactly(endMessageStreamStub, tabId, '', {
            header: undefined,
            buttons: undefined,
            body: 'some response',
            followUp: {},
            relatedContent: undefined,
            canBeVoted: undefined,
            codeReference: undefined,
            fileList: undefined,
        });
        sinon_1.assert.calledOnceWithExactly(updateStoreStub, tabId, {
            loadingChat: false,
            promptInputDisabledState: false,
            cancelButtonWhenLoading: true,
        });
    });
    it('partial chat response triggers ui events', () => {
        const endMessageStreamStub = sandbox.stub(mynahUi, 'endMessageStream');
        const updateStoreStub = sandbox.stub(mynahUi, 'updateStore');
        const tabId = '123';
        const body = 'some response';
        const chatEvent = createInboundEvent({
            command: language_server_runtimes_types_1.CHAT_REQUEST_METHOD,
            tabId,
            params: { body },
            isPartialResult: true,
        });
        window.dispatchEvent(chatEvent);
        sinon_1.assert.notCalled(endMessageStreamStub);
        sinon_1.assert.calledOnce(updateStoreStub);
    });
    it('partial chat response with header triggers ui events', () => {
        const endMessageStreamStub = sandbox.stub(mynahUi, 'endMessageStream');
        const updateStoreStub = sandbox.stub(mynahUi, 'updateStore');
        const tabId = '123';
        const body = 'some response';
        const contextList = {
            filePaths: ['file1', 'file2'],
            details: {
                file1: {
                    lineRanges: [{ first: 1, second: 2 }],
                },
            },
        };
        const params = { body, contextList };
        const mockHeader = {
            fileList: {
                fileTreeTitle: '',
                filePaths: ['file1', 'file2'],
                rootFolderTitle: 'Context',
                flatList: true,
                collapsed: true,
                hideFileCount: true,
                details: {
                    file1: {
                        label: 'line 1 - 2',
                        description: 'file1',
                        clickable: true,
                    },
                },
            },
        };
        const chatEvent = createInboundEvent({
            command: language_server_runtimes_types_1.CHAT_REQUEST_METHOD,
            tabId,
            params,
            isPartialResult: true,
        });
        window.dispatchEvent(chatEvent);
        sinon_1.assert.notCalled(endMessageStreamStub);
        sinon_1.assert.calledOnce(updateStoreStub);
    });
    describe('chatOptions', () => {
        it('enables history and export features support', () => {
            const chatOptionsRequest = createInboundEvent({
                command: chat_client_ui_types_1.CHAT_OPTIONS,
                params: {
                    history: true,
                    export: true,
                },
            });
            window.dispatchEvent(chatOptionsRequest);
            // @ts-ignore
            sinon_1.assert.called(tabFactory_1.TabFactory.prototype.enableHistory);
            // @ts-ignore
            sinon_1.assert.called(tabFactory_1.TabFactory.prototype.enableExport);
        }).timeout(20000);
        it('does not enable history and export features support if flags are falsy', async () => {
            const chatOptionsRequest = createInboundEvent({
                command: chat_client_ui_types_1.CHAT_OPTIONS,
                params: {
                    history: false,
                    export: false,
                },
            });
            window.dispatchEvent(chatOptionsRequest);
            // @ts-ignore
            sinon_1.assert.notCalled(tabFactory_1.TabFactory.prototype.enableHistory);
            // @ts-ignore
            sinon_1.assert.notCalled(tabFactory_1.TabFactory.prototype.enableExport);
        }).timeout(20000);
    });
    describe('onGetSerializedChat', () => {
        it('getSerializedChat requestId was propagated from inbound to outbound message', () => {
            const requestId = 'request-1234';
            const tabId = mynahUi.updateStore('', {});
            const setSerializedChatEvent = createInboundEvent({
                command: language_server_runtimes_types_1.GET_SERIALIZED_CHAT_REQUEST_METHOD,
                params: {
                    tabId: tabId,
                    format: 'markdown',
                },
                requestId: requestId,
            });
            window.dispatchEvent(setSerializedChatEvent);
            // Verify that postMessage was called with the correct requestId
            sinon_1.assert.calledWithExactly(clientApi.postMessage, {
                requestId,
                command: language_server_runtimes_types_1.GET_SERIALIZED_CHAT_REQUEST_METHOD,
                params: {
                    success: true,
                    result: sinon.match({
                        content: sinon.match.string,
                    }),
                },
            });
        });
    });
    function createInboundEvent(params) {
        const event = new CustomEvent('message');
        event.data = params;
        return event;
    }
    describe('with client adapter', () => {
        it('should route inbound message to client adapter', () => {
            const handleMessageReceiveStub = sandbox.stub();
            const createChatEventHandlerStub = sandbox.stub().returns({});
            const clientAdapter = {
                createChatEventHandler: createChatEventHandlerStub,
                handleMessageReceive: handleMessageReceiveStub,
                isSupportedTab: () => false,
            };
            mynahUi = (0, chat_1.createChat)(clientApi, {
                agenticMode: true,
            }, clientAdapter);
            const tabId = '123';
            const body = 'some response';
            const chatEvent = createInboundEvent({
                command: language_server_runtimes_types_1.CHAT_REQUEST_METHOD,
                tabId,
                params: { body },
                sender: 'ide-extension',
            });
            window.dispatchEvent(chatEvent);
            sinon_1.assert.calledOnce(handleMessageReceiveStub);
            sinon_1.assert.match(handleMessageReceiveStub.getCall(0).args[0].data, JSON.stringify(chatEvent.data));
        });
    });
});
//# sourceMappingURL=chat.test.js.map