import { getPartnerEngineConfig } from "@boldpenguin/sdk-redux";
import { BpEnvironmentName } from "@boldpenguin/sdk-types";
import { newSpecPage } from "@stencil/core/testing";
import { BpSdkAutocompleteNaicsContainer } from "./bp-sdk-autocomplete-naics-container";
let fakeStore;
const setupPage = async () => {
    return await newSpecPage({
        html: '<bp-sdk-autocomplete-naics-container question-id="1"></bp-sdk-autocomplete-naics-container>',
        components: [BpSdkAutocompleteNaicsContainer],
    });
};
const setupInstance = (page, overrideStore) => {
    var _a;
    if (overrideStore) {
        fakeStore = overrideStore;
    }
    else {
        fakeStore = {
            application: {
                choices: {},
            },
            config: { uri: 'https://test.local/', env: BpEnvironmentName.Alpha },
            auth: { token: 'testToken', expiresAt: 0 },
        };
    }
    const instance = page.rootInstance;
    instance.remoteChoices = ((_a = fakeStore.application.choices[instance.questionId]) === null || _a === void 0 ? void 0 : _a.list) || [];
    instance.config = {
        token: fakeStore.auth.token,
        uri: fakeStore.config.uri,
        env: fakeStore.config.env,
    };
    instance.onChoicesChange = jest.fn();
    instance.storeUnsubscribe = jest.fn();
    jest.spyOn(instance, 'searchChoices').mockImplementation(jest.fn());
    return instance;
};
describe('BpSdkAutocompleteNaicsContainer', () => {
    beforeEach(() => {
        fakeStore = {
            application: {
                choices: {},
            },
            config: { uri: 'https://test.local/', env: BpEnvironmentName.Alpha },
            auth: { token: 'testToken', expiresAt: 0 },
        };
    });
    describe('render', () => {
        it('should render', async () => {
            const page = await setupPage();
            await page.waitForChanges();
            expect(page.rootInstance).toBeTruthy();
        });
        it('renders external component if defined', async () => {
            jest.spyOn(customElements, 'whenDefined').mockResolvedValueOnce({});
            const page = await setupPage();
            await page.waitForChanges();
            const element = page.root.querySelector('div');
            expect(element).toBeFalsy();
        });
        it('should render when questionId matches available choices', async () => {
            const page = await setupPage();
            fakeStore = Object.assign(Object.assign({}, fakeStore), { application: {
                    choices: {
                        'test-question-id': {
                            list: [{ id: 'some' }, { id: 'items' }],
                            timestamp: 100,
                        },
                    },
                } });
            const instance = setupInstance(page, fakeStore);
            instance.questionId = 'test-question-id';
            instance.remoteChoices = fakeStore.application.choices['test-question-id'].list;
            await page.waitForChanges();
            expect(instance.composedChoices).toEqual(fakeStore.application.choices[instance.questionId].list);
        });
        it('should have choices fallback', async () => {
            fakeStore = Object.assign(Object.assign({}, fakeStore), { application: {
                    choices: {
                        '1': {
                            list: undefined,
                            timestamp: 100,
                        },
                    },
                } });
            const page = await setupPage();
            await page.waitForChanges();
            expect(page.rootInstance.remoteChoices).toEqual([]);
        });
    });
    describe('componentWillLoad', () => {
        it('has fallbacks', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.choices = undefined;
            expect(instance.onChoicesChange).toBeCalledTimes(1);
            instance.componentWillLoad();
            expect(instance.onChoicesChange).toBeCalledTimes(2);
            expect(instance.onChoicesChange).toBeCalledWith([]);
        });
    });
    describe('mapStateToProps', () => {
        it('returns config', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const result = instance.mapStateToProps(fakeStore);
            expect(result.config).toEqual(Object.assign(Object.assign({}, fakeStore.config), { token: fakeStore.auth.token }));
        });
        it('returns remoteChoices', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            fakeStore.application.choices = Object.assign(Object.assign({}, fakeStore.application.choices), { test: {
                    list: ['some', 'choices'],
                    timestamp: 0,
                } });
            instance.questionId = 'test';
            const result = instance.mapStateToProps(fakeStore);
            const list = fakeStore.application.choices['test'].list;
            expect(result.remoteChoices).toEqual(list);
        });
    });
    describe('disconnectedCallback', () => {
        it('makes expected calls', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.disconnectedCallback();
            expect(instance.storeUnsubscribe).toBeCalledTimes(1);
        });
    });
    describe('onFilterUpdate', () => {
        it('makes expected calls', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.questionId = 'an id';
            const value = 'some filter';
            jest.spyOn(Date, 'now').mockReturnValue(100);
            instance.onFilterUpdate({
                detail: {
                    value,
                },
            });
            expect(instance.searchChoices).toBeCalledTimes(1);
            expect(instance.searchChoices).toBeCalledWith({
                config: getPartnerEngineConfig(fakeStore),
                questionId: instance.questionId,
                filter: value,
                timestamp: 100,
            });
        });
        it('disables on useExternal', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.questionId = 'an id';
            instance.useExternal = true;
            const value = 'some filter';
            instance.onFilterUpdate({
                detail: {
                    value,
                },
            });
            expect(instance.searchChoices).toBeCalledTimes(0);
        });
    });
    describe('onChoiceMapUpdate', () => {
        it('update expected properties with expected result', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.questionId = '1';
            instance.choiceId = '2';
            const questionChoices = [
                { id: '0', value: '0' },
                { id: '1', value: '1' },
            ];
            const choiceChoices = [{ id: '1', value: '1', description: 'bob', order: '0' }];
            instance.remoteChoices = choiceChoices;
            instance.onChoiceMapUpdate({
                '2': questionChoices,
            });
            await page.waitForChanges();
            expect(instance.composedChoices).toEqual([choiceChoices[0], questionChoices[0]]);
        });
        it('have expected fallbacks', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.questionId = '0';
            instance.choiceId = '0';
            const choiceChoices = [{ id: '1', value: '1' }];
            instance.remoteChoices = [];
            instance.onChoiceMapUpdate({
                '2': choiceChoices,
            });
            await page.waitForChanges();
            expect(instance.composedChoices).toEqual([]);
        });
    });
    describe('onChoicesUpdate', () => {
        it('update expected properties with expected result', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.questionId = '1';
            instance.choiceId = '2';
            const answerChoices = [{ id: '0', value: '0' }];
            const searchChoices = [
                { id: '0', value: '0', description: 'bob' },
                { id: '1', value: '1', description: 'alice' },
            ];
            instance.choiceMap = {
                '2': answerChoices,
            };
            instance.onChoicesUpdate(searchChoices);
            expect(instance.composedChoices).toEqual([...searchChoices]);
        });
        it('places choices in expected order', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.questionId = '1';
            instance.choiceId = '2';
            const answerChoices = [{ id: '0', value: '0' }];
            const searchChoices = [{ id: '1', value: '1', description: 'alice' }];
            instance.choiceMap = {
                '2': answerChoices,
            };
            instance.onChoicesUpdate(searchChoices);
            expect(instance.composedChoices).toEqual([...searchChoices, ...answerChoices]);
        });
        it('have expected fallbacks', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.questionId = '0';
            instance.choiceId = '0';
            const choiceChoices = [{ id: '1', value: '1' }];
            instance.remoteChoices = [];
            instance.choiceMap = {
                '2': choiceChoices,
            };
            instance.onChoicesUpdate([]);
            expect(instance.composedChoices).toEqual([]);
        });
    });
});
