import { SdkAnalyticsVariables } from "@boldpenguin/sdk-types";
import { newSpecPage } from "@stencil/core/testing";
import { BpSdkAnalyticsContainer } from "./bp-sdk-analytics-container";
const setupPage = async () => {
    return await newSpecPage({
        html: '<bp-sdk-analytics-container></bp-sdk-analytics-container>',
        components: [BpSdkAnalyticsContainer],
    });
};
const setupInstance = (page) => {
    const instance = page.rootInstance;
    return instance;
};
const setupWindow = (pageMock, trackMock, identifyMock, getItemMock, setItemMock) => {
    global.window.BpSdk = {
        analytics: {
            page: pageMock,
            track: trackMock,
            identify: identifyMock,
            storage: {
                getItem: getItemMock,
                setItem: setItemMock,
            },
        },
    };
};
describe('bp-sdk-analytics-container', () => {
    let pageMock = jest.fn();
    let trackMock = jest.fn();
    let identifyMock = jest.fn();
    let getItemMock = jest.fn();
    let setItemMock = jest.fn();
    afterEach(() => {
        jest.resetAllMocks();
    });
    describe('truncate', () => {
        it('should return a short string', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.truncate('test1234')).toEqual('test1234');
        });
        it('should truncate a string longer than 140 characters', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const testString = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient.';
            const oneForty = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et ma';
            expect(instance.truncate(testString)).toEqual(oneForty);
        });
    });
    describe('handleAnalyticsPage', () => {
        it('calls page on the analytics library if it exists', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            const pageData = {};
            instance.handleAnalyticsPage({ detail: { pageData } });
            expect(pageMock).toHaveBeenCalledWith(pageData);
        });
        it('handles analytics missing', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const pageData = {};
            expect(() => instance.handleAnalyticsPage({ detail: { pageData } })).not.toThrowError();
            expect(pageMock).not.toHaveBeenCalled();
        });
        it('handles pageData missing', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            const pageData = undefined;
            instance.handleAnalyticsPage({ detail: { pageData } });
            expect(() => instance.handleAnalyticsPage({ detail: { pageData } })).not.toThrowError();
            expect(pageMock).not.toHaveBeenCalled();
        });
    });
    describe('handleIdentify', () => {
        it('calls identify on the analytics library if it exists', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            const fakeEvent = { detail: { userId: 'testId', traits: {}, options: {} } };
            instance.handleIdentify(fakeEvent);
            expect(identifyMock).toHaveBeenCalledWith(fakeEvent.detail.userId, fakeEvent.detail.traits, fakeEvent.detail.options);
        });
        it('handles analytics missing', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const fakeEvent = { detail: { userId: 'testId', traits: {}, options: {} } };
            expect(() => instance.handleIdentify(fakeEvent)).not.toThrowError();
            expect(identifyMock).not.toHaveBeenCalled();
        });
        it('handles userId missing', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            const fakeEvent = { detail: { userId: undefined, traits: {}, options: {} } };
            instance.handleIdentify(fakeEvent);
            expect(identifyMock).not.toHaveBeenCalled();
            expect(() => instance.handleIdentify(fakeEvent)).not.toThrowError();
        });
        it('defaults missing traits/options', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            const fakeEvent = { detail: { userId: 'testUserId', traits: undefined, options: undefined } };
            instance.handleIdentify(fakeEvent);
            expect(identifyMock).toHaveBeenCalledWith(fakeEvent.detail.userId, {}, {});
        });
    });
    describe('handleTrack', () => {
        it('calls track on the analytics library if it exists', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            const fakeEvent = { detail: { eventName: 'testEvent', eventPayload: {}, eventOptions: {} } };
            instance.handleTrack(fakeEvent);
            expect(trackMock).toHaveBeenCalledWith(fakeEvent.detail.eventName, fakeEvent.detail.eventPayload, fakeEvent.detail.eventOptions);
        });
        it('handles analytics missing', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const fakeEvent = { detail: { eventName: 'testEvent', eventPayload: {}, eventOptions: {} } };
            expect(trackMock).not.toHaveBeenCalled();
            expect(() => instance.handleTrack(fakeEvent)).not.toThrowError();
        });
        it('handles missing eventName', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            const fakeEvent = { detail: { eventName: undefined, eventPayload: {}, eventOptions: {} } };
            instance.handleTrack(fakeEvent);
            expect(trackMock).not.toHaveBeenCalled();
            expect(() => instance.handleTrack(fakeEvent)).not.toThrowError();
        });
        it('defaults payload/options', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            const fakeEvent = { detail: { eventName: 'testEvent', eventPayload: undefined, eventOptions: undefined } };
            instance.handleTrack(fakeEvent);
            expect(trackMock).toHaveBeenCalledWith(fakeEvent.detail.eventName, {}, {});
        });
    });
    describe('handleVariables', () => {
        it('calls track on the analytics library if it exists', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            const fakeVars = { foo: 'bar' };
            const fakeEvent = { detail: fakeVars };
            instance.handleVariables(fakeEvent);
            expect(setItemMock).toHaveBeenCalledWith(SdkAnalyticsVariables.storageKey, fakeVars);
        });
        it('handles analytics missing', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const fakeEvent = { detail: { foo: 'bar' } };
            expect(() => instance.handleVariables(fakeEvent)).not.toThrowError();
        });
    });
    describe('onClick', () => {
        it('calls handleTrack when a button is clicked', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            instance.handleTrack = jest.fn();
            const fakeClickEvent = { target: { tagName: 'BUTTON', innerText: 'testButtonText' } };
            instance.onClick(fakeClickEvent);
            expect(instance.handleTrack).toHaveBeenCalled();
        });
        it('calls handleTrack when a link is clicked', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            instance.handleTrack = jest.fn();
            const fakeClickEvent = { target: { tagName: 'A', innerText: 'testLinkText' } };
            instance.onClick(fakeClickEvent);
            expect(instance.handleTrack).toHaveBeenCalled();
        });
        it('does not call handleTrack when a div is clicked', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            instance.handleTrack = jest.fn();
            const fakeClickEvent = { target: { tagName: 'DIV', innerText: 'testDivText' } };
            instance.onClick(fakeClickEvent);
            expect(instance.handleTrack).not.toHaveBeenCalled();
        });
        it('handles a missing tagname', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
            instance.handleTrack = jest.fn();
            const fakeClickEvent = { target: { innerText: 'testButtonText' } };
            instance.onClick(fakeClickEvent);
            expect(instance.handleTrack).not.toHaveBeenCalled();
        });
    });
    describe('onInput', () => {
        let fakeInputEvent;
        let fakeQuestion;
        beforeEach(() => {
            fakeQuestion = {
                code: 'testQuestionCode',
                text: 'testQuestionText',
                trackable: true,
                choices: [{ id: 'fakeChoiceId' }],
            };
            fakeInputEvent = {
                target: {
                    tagName: 'INPUT',
                    type: 'text',
                    innerText: 'testTextInput',
                    closest: jest.fn(() => ({
                        answer: {
                            choice_id: 'fakeChoiceId',
                            question: fakeQuestion,
                            value: 'testAnswerValue',
                        },
                    })),
                },
            };
        });
        describe('textbox', () => {
            it('calls handleTrack when a textbox changes', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'TextBoxChange',
                        eventPayload: {
                            dataValue: 'testAnswerValue',
                            dt: 'testQuestionText',
                            label: 'testQuestionCode',
                            value: 0,
                        },
                    },
                }));
            });
            it('handles when an answer is not found', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeInputEvent.target.closest = jest.fn();
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'TextBoxChange',
                        eventPayload: {
                            dataValue: '',
                            dt: '',
                            label: '',
                            value: 0,
                        },
                    },
                }));
            });
        });
        describe('textarea', () => {
            it('calls handleTrack when a textarea changes', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeInputEvent.target.type = 'textarea';
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'TextBoxChange',
                        eventPayload: {
                            dataValue: 'testAnswerValue',
                            dt: 'testQuestionText',
                            label: 'testQuestionCode',
                            value: 0,
                        },
                    },
                }));
            });
        });
        describe('radio', () => {
            it('calls handleTrack when a radio button changes', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeInputEvent.target.type = 'radio';
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'RadioButtonChange',
                        eventPayload: {
                            dataValue: undefined,
                            dt: 'testQuestionText',
                            label: 'testQuestionCode',
                            value: 0,
                        },
                    },
                }));
            });
            it('handles when an answer is not found', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeInputEvent.target.type = 'radio';
                fakeInputEvent.target.closest = jest.fn();
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'RadioButtonChange',
                        eventPayload: {
                            dataValue: '',
                            dt: '',
                            label: '',
                            value: 0,
                        },
                    },
                }));
            });
            it('handles when choice_id is not set', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeInputEvent = {
                    target: {
                        tagName: 'INPUT',
                        type: 'radio',
                        innerText: 'testTextInput',
                        closest: jest.fn(() => ({
                            answer: {
                                choice_id: undefined,
                                question: fakeQuestion,
                                value: 'testAnswerValue',
                            },
                        })),
                    },
                };
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'RadioButtonChange',
                        eventPayload: {
                            dataValue: '',
                            dt: 'testQuestionText',
                            label: 'testQuestionCode',
                            value: 0,
                        },
                    },
                }));
            });
        });
        describe('checkbox', () => {
            it('calls handleTrack when a checkbox checks', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeInputEvent.target.type = 'checkbox';
                instance.onInput({
                    target: {
                        tagName: 'INPUT',
                        type: 'checkbox',
                        innerText: 'testTextInput',
                        closest: jest.fn(() => ({
                            answer: {
                                value: 'true',
                                question: fakeQuestion,
                            },
                        })),
                    },
                });
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'BoxCheck',
                        eventPayload: {
                            dataValue: 'Check',
                            dt: 'testQuestionText',
                            label: 'testQuestionCode',
                            value: 0,
                        },
                    },
                }));
            });
            it('calls handleTrack when a checkbox unchecks', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeInputEvent.target.type = 'checkbox';
                instance.onInput({
                    target: {
                        tagName: 'INPUT',
                        type: 'checkbox',
                        innerText: 'testTextInput',
                        closest: jest.fn(() => ({
                            answer: {
                                value: null,
                                question: fakeQuestion,
                            },
                        })),
                    },
                });
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'BoxCheck',
                        eventPayload: {
                            dataValue: 'Uncheck',
                            dt: 'testQuestionText',
                            label: 'testQuestionCode',
                            value: 0,
                        },
                    },
                }));
            });
            it('handles when an answer is not found', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeInputEvent.target.type = 'checkbox';
                fakeInputEvent.target.closest = jest.fn();
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'BoxCheck',
                        eventPayload: {
                            dataValue: 'Uncheck',
                            dt: '',
                            label: '',
                            value: 0,
                        },
                    },
                }));
            });
        });
        describe('select', () => {
            beforeEach(() => {
                fakeQuestion = {
                    code: 'testQuestionCode',
                    text: 'testQuestionText',
                    trackable: true,
                    choices: [{ id: 'fakeChoiceId', value: 'fakeChoiceValue' }],
                    multiple: true,
                };
                fakeInputEvent = {
                    target: {
                        tagName: 'SELECT',
                        innerText: 'testTextInput',
                        closest: jest.fn(() => ({
                            answer: {
                                choice_id: 'fakeChoiceId',
                                choice_ids: ['fakeChoiceId'],
                                question: fakeQuestion,
                            },
                        })),
                    },
                };
            });
            it('calls handleTrack when a multiple select changes', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'DropdownChange',
                        eventPayload: {
                            dataValue: 'fakeChoiceValue',
                            dt: 'testQuestionText',
                            label: 'testQuestionCode',
                            value: 0,
                        },
                    },
                }));
            });
            it('calls handleTrack when a single select changes', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeQuestion = {
                    code: 'testQuestionCode',
                    text: 'testQuestionText',
                    trackable: true,
                    choices: [{ id: 'fakeChoiceId', value: 'fakeChoiceValue' }],
                    multiple: false,
                };
                fakeInputEvent = {
                    target: {
                        tagName: 'SELECT',
                        innerText: 'testTextInput',
                        closest: jest.fn(() => ({
                            answer: {
                                choice_id: 'fakeChoiceId',
                                question: fakeQuestion,
                            },
                        })),
                    },
                };
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).toHaveBeenCalledWith(expect.objectContaining({
                    detail: {
                        eventName: 'DropdownChange',
                        eventPayload: {
                            dataValue: 'fakeChoiceValue',
                            dt: 'testQuestionText',
                            label: 'testQuestionCode',
                            value: 0,
                        },
                    },
                }));
            });
        });
        describe('default', () => {
            it('doesnt call handleTrack', async () => {
                const page = await setupPage();
                const instance = setupInstance(page);
                setupWindow(pageMock, trackMock, identifyMock, getItemMock, setItemMock);
                instance.handleTrack = jest.fn();
                fakeInputEvent.target.tagName = 'uncoveredTag';
                instance.onInput(fakeInputEvent);
                expect(instance.handleTrack).not.toHaveBeenCalled();
            });
        });
    });
});
