jest.mock('@boldpenguin/sdk-utility', () => (Object.assign({
    // eslint-disable-next-line @typescript-eslint/naming-convention
    __esModule: true
}, jest.requireActual('@boldpenguin/sdk-utility'))));
import * as utils from "@boldpenguin/sdk-utility";
import { newSpecPage } from "@stencil/core/testing";
import { BpSdkVehicleConfigurations } from "../bp-sdk-vehicle-configurations/bp-sdk-vehicle-configurations";
import { BpSdkVehicleConfigurationsContainer } from "./bp-sdk-vehicle-configurations-container";
const fakeStore = {
    viewState: {
        vehicleOptions: {
            selection: {
                testId: {
                    yearId: 2018,
                    makeId: '53',
                    modelId: '436357',
                    configurationId: '1440364',
                },
            },
            configurations: {
                testId: {},
            },
            makes: {
                testId: {},
            },
            models: {
                testId: {},
            },
        },
    },
};
const setupPage = async (additionalComponents = []) => {
    return await newSpecPage({
        html: '<bp-sdk-vehicle-configurations-container question-group-id="testId" check-ymm="false"></bp-sdk-vehicle-configurations-container>',
        components: [BpSdkVehicleConfigurationsContainer, ...additionalComponents],
    });
};
const setupInstance = (page) => {
    const instance = page.rootInstance;
    instance.configurationOptions = { test: 'test' };
    instance.selectedVehicle = {
        yearId: 2018,
        makeId: '53',
        modelId: '436357',
        configurationId: '1440364',
    };
    instance.storeUnsubscribe = jest.fn();
    return instance;
};
describe('bp-sdk-vehicle-configurations-container', () => {
    it('renders', async () => {
        const page = await setupPage();
        const instance = setupInstance(page);
        instance.configurationOptions = {
            test: 'test',
        };
        await page.waitForChanges();
        expect(page.root).toEqualHtml(`<bp-sdk-vehicle-configurations-container  question-group-id="testId" check-ymm="false">
        <bp-sdk-vehicle-configurations answeredbysource="" label="Choose vehicle configuration" pristine="" selectedconfigurationid="1440364">
        </bp-sdk-vehicle-configurations>
      </bp-sdk-vehicle-configurations-container>`);
    });
    it('does not renders if checkymm and missing ymm info', async () => {
        const page = await setupPage();
        const instance = setupInstance(page);
        instance.checkYmm = true;
        await page.waitForChanges();
        expect(page.root).toEqualHtml(`<bp-sdk-vehicle-configurations-container question-group-id="testId" check-ymm="false"></bp-sdk-vehicle-configurations-container>`);
    });
    it('does not renders if checkymm and missing ymm info values', async () => {
        const page = await setupPage();
        const instance = setupInstance(page);
        instance.checkYmm = true;
        instance.configurationOptions = { test: 'test' };
        instance.makeOptions = {};
        instance.modelOptions = {};
        await page.waitForChanges();
        expect(page.root).toEqualHtml(`<bp-sdk-vehicle-configurations-container question-group-id="testId" check-ymm="false"></bp-sdk-vehicle-configurations-container>`);
    });
    it('does renders if checkymm and ymm info is present', async () => {
        const page = await setupPage();
        const instance = setupInstance(page);
        instance.configurationOptions = { test: 'test', configs: 'configs' };
        instance.makeOptions = { 'some model': 'some model' };
        instance.modelOptions = { 'some make': 'some make' };
        instance.checkYmm = true;
        await page.waitForChanges();
        expect(page.root).toEqualHtml(`<bp-sdk-vehicle-configurations-container question-group-id="testId" check-ymm="false">
          <bp-sdk-vehicle-configurations answeredbysource="" label="Choose vehicle configuration" pristine="" selectedconfigurationid="1440364">
          </bp-sdk-vehicle-configurations>
        </bp-sdk-vehicle-configurations-container>`);
    });
    it('does renders if checkymm and ymm info is present and no selection', async () => {
        const page = await setupPage();
        const instance = setupInstance(page);
        instance.selectedVehicle = undefined;
        instance.configurationOptions = { test: 'test', configs: 'configs' };
        instance.makeOptions = { 'some model': 'some model' };
        instance.modelOptions = { 'some make': 'some make' };
        instance.checkYmm = true;
        await page.waitForChanges();
        expect(page.root).toEqualHtml(`<bp-sdk-vehicle-configurations-container question-group-id="testId" check-ymm="false">
          <bp-sdk-vehicle-configurations answeredbysource="" label="Choose vehicle configuration" pristine="" >
          </bp-sdk-vehicle-configurations>
        </bp-sdk-vehicle-configurations-container>`);
    });
    it('renders no configurations', async () => {
        const page = await setupPage();
        const instance = setupInstance(page);
        instance.configurationOptions = {};
        await page.waitForChanges();
        expect(page.root).toEqualHtml(`
        <bp-sdk-vehicle-configurations-container question-group-id="testId" check-ymm="false">
          <bp-sdk-vehicle-configurations answeredbysource="" label="Choose vehicle configuration" pristine="" selectedconfigurationid="1440364">
          </bp-sdk-vehicle-configurations>
        </bp-sdk-vehicle-configurations-container>
        `);
    });
    it('renders no options', async () => {
        const page = await setupPage();
        const instance = setupInstance(page);
        instance.configurationOptions = {};
        instance.makeOptions = {};
        instance.makeOptions = {};
        instance.modelOptions = {};
        instance.selectedVehicle = {};
        await page.waitForChanges();
        expect(page.root).toEqualHtml(`<bp-sdk-vehicle-configurations-container question-group-id="testId" check-ymm="false">
        <bp-sdk-vehicle-configurations answeredbysource="" label="Choose vehicle configuration" pristine=""></bp-sdk-vehicle-configurations>
      </bp-sdk-vehicle-configurations-container>`);
    });
    it('passes model id', async () => {
        const page = await setupPage();
        const instance = setupInstance(page);
        instance.selectedVehicle = {
            configurationId: 'id',
        };
        await page.waitForChanges();
        expect(page.root).toEqualHtml(`<bp-sdk-vehicle-configurations-container question-group-id="testId" check-ymm="false">
        <bp-sdk-vehicle-configurations answeredbysource="" label="Choose vehicle configuration" pristine="" selectedconfigurationid="id"></bp-sdk-vehicle-configurations>
      </bp-sdk-vehicle-configurations-container>`);
    });
    it('renders external component if defined', async () => {
        const whenDefinedMock = jest.spyOn(customElements, 'whenDefined').mockResolvedValueOnce({});
        const page = await setupPage();
        const element = page.root.querySelector('bp-sdk-external-vehicle-configurations-container');
        expect(element).toBeTruthy();
        whenDefinedMock.mockRestore();
    });
    describe('componentDidLoad', () => {
        it('makes expected calls', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance, 'loadFocusEvents').mockImplementation(() => { });
            instance.componentDidLoad();
            expect(instance.loadFocusEvents).toBeCalledTimes(1);
        });
    });
    describe('disconnectedCallback', () => {
        it('makes expected calls', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance, 'unloadFocusEvents').mockImplementation(() => { });
            instance.disconnectedCallback();
            expect(instance.unloadFocusEvents).toBeCalledTimes(1);
        });
    });
    describe('onUseExternalChange', () => {
        it('makes expected calls if true', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance, 'unloadFocusEvents').mockImplementation(() => { });
            instance.onUseExternalChange(true);
            expect(instance.unloadFocusEvents).toBeCalledTimes(0);
        });
        it('makes expected calls if false', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance, 'unloadFocusEvents').mockImplementation(() => { });
            instance.onUseExternalChange(false);
            expect(instance.unloadFocusEvents).toBeCalledTimes(1);
        });
    });
    describe('onMakeDirty', () => {
        it('should ignore unchanged touched state', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.touched = false;
            instance.pristine = true;
            instance.onMakeDirty();
            expect(instance.touched).toBeTruthy();
            expect(instance.pristine).toBeFalsy();
        });
    });
    describe('loadFocusEvents', () => {
        it('sets expected values', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.useExternal = false;
            jest.spyOn(instance.el, 'addEventListener').mockReturnValue();
            await page.waitForChanges();
            instance.loadFocusEvents();
            expect(instance.el.addEventListener).toBeCalledTimes(1);
            expect(instance.el.addEventListener).toBeCalledWith('focusout', instance.onFocusOut);
        });
        it('handles truthy useExternal', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.useExternal = true;
            jest.spyOn(instance.el, 'addEventListener').mockReturnValue();
            await page.waitForChanges();
            instance.loadFocusEvents();
            expect(instance.el.addEventListener).toBeCalledTimes(0);
        });
    });
    describe('unloadFocusEvents', () => {
        it('sets expected values', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance.el, 'removeEventListener').mockImplementation(() => { });
            await page.waitForChanges();
            instance.unloadFocusEvents();
            expect(instance.el.removeEventListener).toBeCalledTimes(1);
            expect(instance.el.removeEventListener).toBeCalledWith('focusout', instance.onFocusOut);
        });
    });
    describe('onValueUpdate', () => {
        let updateEvent;
        beforeEach(() => {
            updateEvent = {
                detail: [''],
                stopPropagation: jest.fn(),
            };
        });
        it('sets expected values', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.pristine = true;
            instance.onValueUpdate(updateEvent);
            expect(instance.pristine).toBeFalsy();
            expect(instance.value).toEqual('');
        });
        it('handled no details', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.pristine = true;
            instance.onValueUpdate(Object.assign(Object.assign({}, updateEvent), { detail: undefined }));
            expect(instance.pristine).toBeFalsy();
            expect(instance.value).toBeUndefined();
        });
        it('handles truthy useExternal', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.useExternal = true;
            instance.pristine = true;
            instance.onValueUpdate(updateEvent);
            expect(instance.pristine).toBeTruthy();
            expect(instance.value).toBeUndefined();
        });
        it('emits event if no errors', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.spyOn(instance.ymmcUpdate, 'emit').mockReturnValue(null);
            instance.onValueUpdate(updateEvent);
            expect(instance.ymmcUpdate.emit).toHaveBeenCalledWith({ type: 'configuration', value: '' });
        });
        it('does not emit event if there are errors', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.errors = ['required'];
            jest.spyOn(instance, 'updateErrors').mockReturnValue(null);
            jest.spyOn(instance.ymmcUpdate, 'emit').mockReturnValue(null);
            instance.onValueUpdate(updateEvent);
            expect(instance.ymmcUpdate.emit).not.toHaveBeenCalled();
        });
        it('updates errors if value would fix required error', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.errors = ['required'];
            jest.spyOn(instance.ymmcUpdate, 'emit').mockReturnValue(null);
            instance.onValueUpdate({ detail: ['test'], stopPropagation: () => { } });
            expect(instance.ymmcUpdate.emit).toHaveBeenCalledWith({ type: 'configuration', value: 'test' });
        });
    });
    describe('onFocusOut', () => {
        it('sets expected values', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.touched = false;
            instance.onFocusOut();
            expect(instance.touched).toBeTruthy();
        });
    });
    describe('updateErrors', () => {
        it('returns required if error determined', async () => {
            jest.spyOn(utils, 'hasRequiredError').mockReturnValue(true);
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            instance.updateErrors(false, false, '');
            expect(instance.errors).toEqual(['required']);
        });
        it('otherwise empty state', async () => {
            jest.spyOn(utils, 'hasRequiredError').mockReturnValue(false);
            const page = await setupPage();
            const instance = setupInstance(page);
            await page.waitForChanges();
            instance.updateErrors(false, false, '');
            expect(instance.errors).toEqual([]);
        });
    });
    describe('convertConfigurationsToChoices', () => {
        it('converts years to IChoice array', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const configurations = { '1234': 'Test1', '4321': 'Test2' };
            expect(instance.convertConfigurationsToChoices(configurations)).toEqual([
                { id: '1234', value: 'Test1' },
                { id: '4321', value: 'Test2' },
            ]);
        });
        it('returns empty array if there are no configurations', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.convertConfigurationsToChoices({})).toEqual([]);
        });
    });
    describe('mapStateToProps', () => {
        it('returns vehicleOptions', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const result = instance.mapStateToProps(fakeStore);
            expect(result.configurationOptions).toEqual(fakeStore.viewState.vehicleOptions.configurations.testId);
            expect(result.makeOptions).toEqual(fakeStore.viewState.vehicleOptions.makes.testId);
            expect(result.modelOptions).toEqual(fakeStore.viewState.vehicleOptions.models.testId);
            expect(result.selectedVehicle).toEqual(fakeStore.viewState.vehicleOptions.selection.testId);
        });
    });
    describe('internal state', () => {
        it('passes along code', async () => {
            const page = await setupPage([BpSdkVehicleConfigurations]);
            const instance = setupInstance(page);
            instance.code = 'oldCode';
            await page.waitForChanges();
            const ele = page.root.querySelector('bp-sdk-dynamic-input');
            expect(ele).toEqualAttribute('code', 'oldCode');
        });
    });
    describe('handleSubscriptions', () => {
        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('subscribes 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(unsubscribe).toHaveBeenCalledTimes(1);
            expect(instance.storeUnsubscribe).not.toBe(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);
        });
    });
    describe('isReadyToConfigure', () => {
        it('sets true if makes and models', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.isReadyToConfigure({
                configurations: { something: 'some', configurations: 'configurations' },
                makes: { something: 'something' },
                models: { something: 'something' },
            })).toBeTruthy();
        });
        it('sets false if only one configuration as it will be automatically emitted', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.isReadyToConfigure({
                configurations: { something: 'something' },
                makes: { something: 'something' },
                models: { something: 'something' },
            })).toBeFalsy();
        });
        it('sets false  if no makes', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.isReadyToConfigure({
                configurations: { something: 'something' },
                models: { something: 'something' },
            })).toBeFalsy();
        });
        it('sets false  if no models', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.isReadyToConfigure({
                configurations: { something: 'something' },
                makes: { something: 'something' },
            })).toBeFalsy();
        });
        it('sets false  if no configurations', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.isReadyToConfigure({
                models: { something: 'something' },
                makes: { something: 'something' },
            })).toBeFalsy();
        });
        it('sets false if no makes and models', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.isReadyToConfigure({})).toBeFalsy();
        });
        it('sets false if config missing', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.isReadyToConfigure(undefined)).toBeFalsy();
        });
    });
    describe('onConfigurationsChange', () => {
        it('handles undefined', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.configurationOptions = undefined;
            expect(instance.value).toBeUndefined();
        });
    });
});
