import { LoadingStates, QuoteRequestRequestTypes, StatusState } from "@boldpenguin/sdk-types";
import { newSpecPage } from "@stencil/core/testing";
import { BpSdkCustomEventContainer } from "./bp-sdk-custom-event-container";
const createMockState = (store = {}) => {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
    return (Object.assign(Object.assign({}, store), { application: Object.assign(Object.assign({}, ((_a = store === null || store === void 0 ? void 0 : store.application) !== null && _a !== void 0 ? _a : {})), { form: Object.assign({}, ((_c = (_b = store === null || store === void 0 ? void 0 : store.application) === null || _b === void 0 ? void 0 : _b.form) !== null && _c !== void 0 ? _c : {})), quotes: Object.assign({}, ((_e = (_d = store === null || store === void 0 ? void 0 : store.application) === null || _d === void 0 ? void 0 : _d.quotes) !== null && _e !== void 0 ? _e : {})), questionSets: Object.assign({}, ((_g = (_f = store === null || store === void 0 ? void 0 : store.application) === null || _f === void 0 ? void 0 : _f.questionSets) !== null && _g !== void 0 ? _g : {
                active: 'testActiveQuestionSet',
                list: [],
            })) }), status: Object.assign(Object.assign({}, ((_h = store === null || store === void 0 ? void 0 : store.status) !== null && _h !== void 0 ? _h : Object.assign({}, StatusState))), { remote: Object.assign({}, ((_k = (_j = store === null || store === void 0 ? void 0 : store.status) === null || _j === void 0 ? void 0 : _j.remote) !== null && _k !== void 0 ? _k : {
                application: Object.assign({}, ((_o = (_m = (_l = store === null || store === void 0 ? void 0 : store.status) === null || _l === void 0 ? void 0 : _l.remote) === null || _m === void 0 ? void 0 : _m.application) !== null && _o !== void 0 ? _o : {
                    form: (_s = (_r = (_q = (_p = store === null || store === void 0 ? void 0 : store.status) === null || _p === void 0 ? void 0 : _p.remote) === null || _q === void 0 ? void 0 : _q.application) === null || _r === void 0 ? void 0 : _r.form) !== null && _s !== void 0 ? _s : LoadingStates.Loaded,
                })),
                answers: (_v = (_u = (_t = store === null || store === void 0 ? void 0 : store.status) === null || _t === void 0 ? void 0 : _t.remote) === null || _u === void 0 ? void 0 : _u.answers) !== null && _v !== void 0 ? _v : {
                    map: {},
                },
            })) }), auth: Object.assign({}, ((_w = store === null || store === void 0 ? void 0 : store.auth) !== null && _w !== void 0 ? _w : {})), config: Object.assign({}, ((_x = store === null || store === void 0 ? void 0 : store.config) !== null && _x !== void 0 ? _x : {})) }));
};
describe('bp-sdk-custom-event-container', () => {
    const setupPage = async () => {
        return await newSpecPage({
            html: '<bp-sdk-custom-event-container></bp-sdk-custom-event-container>',
            components: [BpSdkCustomEventContainer],
        });
    };
    const setupInstance = (page) => {
        const instance = page.rootInstance;
        instance.activeQuestionSetChange.emit = jest.fn();
        instance.formLoaded.emit = jest.fn();
        instance.userAuthenticationChanged.emit = jest.fn();
        instance.quotesChanged.emit = jest.fn();
        instance.quoteSuccess.emit = jest.fn();
        instance.quoteFailure.emit = jest.fn();
        instance.answerStateChanged.emit = jest.fn();
        instance.questionSetCompletionChanged.emit = jest.fn();
        instance.questionSetAdded.emit = jest.fn();
        return instance;
    };
    afterEach(() => {
        jest.resetAllMocks();
    });
    describe('render', () => {
        it('renders', async () => {
            const page = await setupPage();
            await page.waitForChanges();
            const element = page.root.querySelector('.bp-sdk-custom-event-container__container');
            expect(element).toBeTruthy();
            expect(page.root.querySelector('bp-sdk-external-custom-event-container')).toBeFalsy();
        });
        it('renders external component if defined', async () => {
            const whenDefinedMock = jest.spyOn(customElements, 'whenDefined').mockResolvedValueOnce({});
            const page = await setupPage();
            expect(page.root.querySelector('bp-sdk-external-custom-event-container')).toBeTruthy();
            whenDefinedMock.mockRestore();
        });
    });
    describe('mapStateToProps', () => {
        it('returns an object with the correct keys', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const result = instance.mapStateToProps(createMockState());
            expect(result).toHaveProperty('activeQuestionSet');
            expect(result).toHaveProperty('applicationForm');
            expect(result).toHaveProperty('isFormLoaded');
            expect(result).toHaveProperty('isUserAuthenticated');
            expect(result).toHaveProperty('quotes');
            expect(result).toHaveProperty('answerResources');
            expect(result).toHaveProperty('questionSets');
        });
    });
    describe('onActiveQuestionSetChange', () => {
        it('emits activeQuestionSetChange', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.onActiveQuestionSetChange({ question_set_id: 'new' }, { question_set_id: 'old' });
            expect(instance.activeQuestionSetChange.emit).toHaveBeenCalled();
        });
        it('does not emit when question set hasnt changed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.onActiveQuestionSetChange({ question_set_id: 'new' }, { question_set_id: 'new' });
            expect(instance.activeQuestionSetChange.emit).not.toHaveBeenCalled();
        });
        it('handles null', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.onActiveQuestionSetChange({ question_set_id: 'new id' }, null);
            expect(instance.activeQuestionSetChange.emit).toHaveBeenCalled();
        });
        it('handles undefined', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.onActiveQuestionSetChange({ question_set_id: 'new id' }, undefined);
            expect(instance.activeQuestionSetChange.emit).toHaveBeenCalled();
        });
        it('handles bad active set value', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.onActiveQuestionSetChange(null, undefined);
            expect(instance.activeQuestionSetChange.emit).not.toHaveBeenCalled();
        });
    });
    describe('onIsFormLoadedChange', () => {
        it('emits formLoaded', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.onIsFormLoadedChange(true);
            expect(instance.formLoaded.emit).toHaveBeenCalled();
        });
        it('doesnt emit if flag is false', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.onIsFormLoadedChange(false);
            expect(instance.formLoaded.emit).not.toHaveBeenCalled();
        });
    });
    describe('onAuthenticatedChange', () => {
        it('emits userAuthenticationChanged: true', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.onAuthenticatedChange(true);
            expect(instance.userAuthenticationChanged.emit).toHaveBeenCalledWith(true);
        });
        it('emits userAuthenticationChanged: false', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.onAuthenticatedChange(false);
            expect(instance.userAuthenticationChanged.emit).toHaveBeenCalledWith(false);
        });
    });
    describe('onQuotesChange', () => {
        it('emits quotesChanged', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuotes = [{ id: 'test' }];
            instance.onQuotesChange(newQuotes, []);
            expect(instance.quotesChanged.emit).toHaveBeenCalledWith(newQuotes);
        });
        it('emits quoteSuccess if existing quote succeeded', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuotes = [{ id: 'existing', request_status: QuoteRequestRequestTypes.completed }];
            const oldQuotes = [{ id: 'existing', request_status: QuoteRequestRequestTypes.in_progress }];
            instance.onQuotesChange(newQuotes, oldQuotes);
            expect(instance.quoteSuccess.emit).toHaveBeenCalledWith(newQuotes[0]);
        });
        it('emits quoteSuccess if new quote succeeded', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuotes = [{ id: 'new', request_status: QuoteRequestRequestTypes.completed }];
            const oldQuotes = [];
            instance.onQuotesChange(newQuotes, oldQuotes);
            expect(instance.quoteSuccess.emit).toHaveBeenCalledWith(newQuotes[0]);
        });
        it('emits quoteFailure if existing quote failed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuotes = [{ id: 'existing', request_status: QuoteRequestRequestTypes.failed }];
            const oldQuotes = [{ id: 'existing', request_status: QuoteRequestRequestTypes.in_progress }];
            instance.onQuotesChange(newQuotes, oldQuotes);
            expect(instance.quoteFailure.emit).toHaveBeenCalledWith(newQuotes[0]);
        });
        it('emits quoteFailure if new quote failed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuotes = [{ id: 'new', request_status: QuoteRequestRequestTypes.failed }];
            const oldQuotes = [];
            instance.onQuotesChange(newQuotes, oldQuotes);
            expect(instance.quoteFailure.emit).toHaveBeenCalledWith(newQuotes[0]);
        });
        it('does not emit success if existing quote stayed the same status', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuotes = [{ id: 'existing', request_status: QuoteRequestRequestTypes.completed }];
            const oldQuotes = [{ id: 'existing', request_status: QuoteRequestRequestTypes.completed }];
            instance.onQuotesChange(newQuotes, oldQuotes);
            expect(instance.quoteSuccess.emit).not.toHaveBeenCalled();
        });
        it('does not emit failure if existing quote stayed the same status', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuotes = [{ id: 'existing', request_status: QuoteRequestRequestTypes.failed }];
            const oldQuotes = [{ id: 'existing', request_status: QuoteRequestRequestTypes.failed }];
            instance.onQuotesChange(newQuotes, oldQuotes);
            expect(instance.quoteFailure.emit).not.toHaveBeenCalled();
        });
    });
    describe('onAnswerResourcesChange', () => {
        it('emits answerStateChanged when existing answer resource changes', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newAnswersResources = { existing: LoadingStates.Loaded };
            const oldAnswersResources = { existing: LoadingStates.Loading };
            instance.onAnswerResourcesChange(newAnswersResources, oldAnswersResources);
            expect(instance.answerStateChanged.emit).toHaveBeenCalledWith({ answerId: 'existing', loadingState: newAnswersResources.existing });
        });
        it('emits answerStateChanged when new resource is added', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newAnswersResources = { new: LoadingStates.Loading };
            const oldAnswersResources = {};
            instance.onAnswerResourcesChange(newAnswersResources, oldAnswersResources);
            expect(instance.answerStateChanged.emit).toHaveBeenCalledWith({ answerId: 'new', loadingState: newAnswersResources.new });
        });
        it('does not emit answerStateChanged if existing resource stays the same', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newAnswersResources = { existing: LoadingStates.Loading };
            const oldAnswersResources = { existing: LoadingStates.Loading };
            instance.onAnswerResourcesChange(newAnswersResources, oldAnswersResources);
            expect(instance.answerStateChanged.emit).not.toHaveBeenCalled();
        });
    });
    describe('onQuestionSetsChange', () => {
        it('emits questionSetAdded when new question set is added', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuestionSets = [{ question_set_id: 'new', is_completed: false }];
            const oldQuestionSets = [];
            instance.onQuestionSetsChange(newQuestionSets, oldQuestionSets);
            expect(instance.questionSetAdded.emit).toHaveBeenCalledWith(newQuestionSets[0]);
        });
        it('emits questionSetCompletionChanged when is_completed changes to true', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuestionSets = [{ question_set_id: 'existing', is_completed: true }];
            const oldQuestionSets = [{ question_set_id: 'existing', is_completed: false }];
            instance.onQuestionSetsChange(newQuestionSets, oldQuestionSets);
            expect(instance.questionSetCompletionChanged.emit).toHaveBeenCalledWith(newQuestionSets[0]);
        });
        it('emits questionSetCompletionChanged when is_completed changes to false', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuestionSets = [{ question_set_id: 'existing', is_completed: false }];
            const oldQuestionSets = [{ question_set_id: 'existing', is_completed: true }];
            instance.onQuestionSetsChange(newQuestionSets, oldQuestionSets);
            expect(instance.questionSetCompletionChanged.emit).toHaveBeenCalledWith(newQuestionSets[0]);
        });
        it('does not emit when is_completed stays the same', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuestionSets = [{ question_set_id: 'existing', is_completed: true }];
            const oldQuestionSets = [{ question_set_id: 'existing', is_completed: true }];
            instance.onQuestionSetsChange(newQuestionSets, oldQuestionSets);
            expect(instance.questionSetCompletionChanged.emit).not.toHaveBeenCalled();
        });
        it('emits if old sets are undefined', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuestionSets = [{ question_set_id: 'existing', is_completed: true }];
            const oldQuestionSets = undefined;
            instance.onQuestionSetsChange(newQuestionSets, oldQuestionSets);
            expect(instance.questionSetCompletionChanged.emit).toHaveBeenCalled();
        });
        it('emits if old sets are null', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuestionSets = [{ question_set_id: 'existing', is_completed: true }];
            const oldQuestionSets = null;
            instance.onQuestionSetsChange(newQuestionSets, oldQuestionSets);
            expect(instance.questionSetCompletionChanged.emit).toHaveBeenCalled();
        });
        it('does nothing if newQuestionSets are falsy', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const newQuestionSets = undefined;
            const oldQuestionSets = undefined;
            instance.onQuestionSetsChange(newQuestionSets, oldQuestionSets);
            expect(instance.questionSetCompletionChanged.emit).not.toHaveBeenCalled();
        });
    });
    describe('handleSubscriptions', () => {
        it('calls subscribe function', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const unsubscribe = jest.fn();
            instance.storeUnsubscribe = unsubscribe;
            instance.handleSubscriptions();
            expect(unsubscribe).toHaveBeenCalled();
        });
        it('subscribes if not subscribed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.storeUnsubscribe = null;
            instance.handleSubscriptions();
            expect(instance.storeUnsubscribe).not.toBeNull();
        });
        it('updates mapStateToProps if already has storeUnsubscribe', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const unsubscribe = jest.fn();
            instance.storeUnsubscribe = unsubscribe;
            instance.handleSubscriptions();
            expect(instance.storeUnsubscribe).toBeDefined();
            expect(instance.storeUnsubscribe).not.toEqual(unsubscribe);
        });
    });
    describe('connectedCallback', () => {
        it('makes expected call if root available', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.handleSubscriptions = jest.fn();
            jest.spyOn(instance.el, 'querySelector').mockImplementationOnce(() => ({
                componentOnReady: () => Promise.resolve(true),
            }));
            instance.connectedCallback();
            await page.waitForChanges();
            expect(instance.handleSubscriptions).toBeCalledTimes(1);
        });
    });
});
