import { AppetiteMarkets, ApplicationFormStates, LoadingStates, QuoteRequestRequestTypes, StatusState, } from "@boldpenguin/sdk-types";
import { newSpecPage } from "@stencil/core/testing";
import { BpSdkQuoteRequestContainer } from "./bp-sdk-quote-request-container";
const fakeStore = {
    application: {
        form: {
            id: 'testFormId',
            state: 'testFormState',
        },
        quotes: [],
        carriersProducts: [],
        questionSets: {
            list: [],
        },
    },
    config: {
        env: 'testenv',
        uri: 'https://test.local',
    },
    auth: {
        token: 'testToken',
    },
    status: Object.assign({}, StatusState),
};
const setupPage = async () => {
    return await newSpecPage({
        html: '<bp-sdk-quote-request-container></bp-sdk-quote-request-container>',
        components: [BpSdkQuoteRequestContainer],
    });
};
const setupInstance = (page) => {
    const instance = page.rootInstance;
    jest.spyOn(instance, 'timeoutQuoteState').mockImplementation(jest.fn());
    jest.spyOn(instance, 'bindQuoteRequest').mockImplementation(jest.fn());
    instance.configOptions = {
        renderOfflineQuotes: true,
        enableQuestionSetNavigation: true,
        quoteStatusFilter: [QuoteRequestRequestTypes.completed],
        enableWebSockets: true,
    };
    instance.carriersProducts = [
        {
            product: {
                id: '3f8dd55f-1ceb-4c12-b00d-6ed4a7595a27',
                name: 'General Liability',
            },
            carrier: {
                id: '1841d2cd-4cd8-410f-91f9-29ef9e44982b',
                name: 'Bold Penguin Off-platform',
                online: false,
                logo_url: 'http://localhost:3000/rails/active_storage/representations/fake-logo.png',
            },
        },
    ];
    return instance;
};
describe('bp-sdk-quote-request-container', () => {
    beforeEach(() => {
        jest.useFakeTimers({ legacyFakeTimers: true });
    });
    describe('renders', () => {
        it('nothing when application and quotes are loading', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.quotesResourceState = LoadingStates.Loading;
            instance.applicationFormResourceState = LoadingStates.Loading;
            await page.waitForChanges();
            expect(instance.isReady).toBeTruthy();
            expect(page.body.querySelectorAll('bp-sdk-quote-request').length).toBe(0);
            expect(page.body.querySelector('bp-sdk-quote-load')).toBeFalsy();
        });
        it('spinner when quotes are loading', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.quotesResourceState = LoadingStates.Loading;
            instance.applicationFormResourceState = LoadingStates.Loaded;
            await page.waitForChanges();
            expect(instance.isReady).toBeFalsy();
            expect(page.body.querySelectorAll('bp-sdk-quote-request').length).toBe(0);
            expect(page.body.querySelector('bp-sdk-quote-load')).toBeTruthy();
        });
        it('is ready', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.quotesResourceState = LoadingStates.Loaded;
            instance.applicationFormResourceState = LoadingStates.Loaded;
            await page.waitForChanges();
            expect(instance.isReady).toBeTruthy();
            expect(page.body.querySelectorAll('bp-sdk-quote-request').length).toBe(0);
            expect(page.body.querySelector('bp-sdk-quote-load')).toBeFalsy();
        });
        it('nothing when quoteStatusFilter is undefined', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.configOptions.quoteStatusFilter = undefined;
            instance.quotes = [
                {
                    carrier: {
                        name: 'carrier',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            await page.waitForChanges();
            expect(instance.isReady).toBeTruthy();
            expect(page.body.querySelectorAll('bp-sdk-quote-request').length).toBe(0);
            expect(page.body.querySelector('bp-sdk-quote-load')).toBeFalsy();
        });
        it('nothing when configOptions is undefined', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.configOptions = undefined;
            instance.quotes = [
                {
                    carrier: {
                        name: 'carrier',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            await page.waitForChanges();
            expect(instance.isReady).toBeTruthy();
            expect(page.body.querySelectorAll('bp-sdk-quote-request').length).toBe(0);
            expect(page.body.querySelector('bp-sdk-quote-load')).toBeFalsy();
        });
        it('unfulfilled', async () => {
            const page = await setupPage();
            await page.waitForChanges();
            expect(page.rootInstance).toBeTruthy();
            expect(page.body.querySelectorAll('bp-sdk-quote-request').length).toBe(0);
        });
        it('renders completed quotes', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.quotes = [
                {
                    carrier: {
                        name: 'carrier',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            await page.waitForChanges();
            expect(page.root.querySelectorAll('bp-sdk-quote-request').length).toBe(1);
        });
        it('filters online quotes', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.filteredCarrierCodes = ['test_carrier_code_1'];
            instance.quotes = [
                {
                    carrier: {
                        name: 'carrier1',
                        code: 'test_carrier_code_1',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
                {
                    carrier: {
                        name: 'carrier2',
                        code: 'test_carrier_code_2',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            await page.waitForChanges();
            expect(page.root.querySelectorAll('bp-sdk-quote-request').length).toBe(1);
        });
        it('offline quotes', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.carriersProducts = [
                {
                    id: 'id_1',
                    application_form_id: 'app_form_id',
                    carrier: {
                        id: 'offline_carrier_id',
                        online: false,
                    },
                    carriers_product_id: 'carriers_product_id',
                    product: {},
                    // legacy: no markets
                },
                {
                    id: 'id_2',
                    application_form_id: 'app_form_id',
                    carrier: {
                        id: 'online_carrier_id',
                        online: true,
                    },
                    carriers_product_id: 'carriers_product_id',
                    product: {},
                    market: AppetiteMarkets.OFFLINE,
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            await page.waitForChanges();
            expect(page.root.querySelectorAll('bp-sdk-offline-quote').length).toBe(2);
        });
        it('filters offline quotes by carrier code', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.filteredCarrierCodes = ['offline_carrier_code'];
            instance.carriersProducts = [
                {
                    id: 'id_1',
                    application_form_id: 'app_form_id',
                    carrier: {
                        id: 'offline_carrier_id',
                        code: 'offline_carrier_code',
                        online: false,
                    },
                    carriers_product_id: 'carriers_product_id',
                    product: {},
                    // legacy: no markets
                },
                {
                    id: 'id_2',
                    application_form_id: 'app_form_id',
                    carrier: {
                        id: 'online_carrier_id',
                        code: 'online_carrier_code',
                        online: true,
                    },
                    carriers_product_id: 'carriers_product_id',
                    product: {},
                    market: AppetiteMarkets.OFFLINE,
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            await page.waitForChanges();
            expect(page.root.querySelectorAll('bp-sdk-offline-quote').length).toBe(1);
        });
        it('no offline quotes when config option is false', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.carriersProducts = [
                {
                    id: 'id_1',
                    application_form_id: 'app_form_id',
                    carrier: {
                        id: 'offline_carrier_id',
                        online: false,
                    },
                    carriers_product_id: 'carriers_product_id',
                    product: {},
                    // legacy: no markets
                },
                {
                    id: 'id_2',
                    application_form_id: 'app_form_id',
                    carrier: {
                        id: 'online_carrier_id',
                        online: true,
                    },
                    carriers_product_id: 'carriers_product_id',
                    product: {},
                    market: AppetiteMarkets.OFFLINE,
                },
            ];
            instance.configOptions.renderOfflineQuotes = false;
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            await page.waitForChanges();
            expect(page.root.querySelectorAll('bp-sdk-offline-quote').length).toBe(0);
        });
        it('renders send to exchange container', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.quotes = [
                {
                    carrier: {
                        name: 'carrier',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            await page.waitForChanges();
            expect(page.root.querySelectorAll('bp-sdk-send-to-exchange-container').length).toBe(1);
        });
        it('does not render send to exchange container when disabled', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.quotes = [
                {
                    carrier: {
                        name: 'carrier',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            instance.disableSendToExchange = true;
            await page.waitForChanges();
            expect(page.root.querySelectorAll('bp-sdk-send-to-exchange-container').length).toBe(0);
        });
        it('renders if app form is in progress and renderQuotesWithAppState', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.quotes = [{ carrier: { name: 'carrier' }, request_status: QuoteRequestRequestTypes.completed }];
            instance.appFormState = ApplicationFormStates.InProgress;
            instance.configOptions = { quoteStatusFilter: [QuoteRequestRequestTypes.completed] };
            instance.isReady = true;
            await page.waitForChanges();
            expect(page.root.querySelector('bp-sdk-quote-request')).toBeNull();
            instance.configOptions = Object.assign(Object.assign({}, instance.configOptions), { renderQuotesWithAppState: [ApplicationFormStates.InProgress] });
            await page.waitForChanges();
            expect(page.root.querySelector('bp-sdk-quote-request')).not.toBeNull();
        });
        it('renders external component if defined', async () => {
            const whenDefinedMock = jest.spyOn(customElements, 'whenDefined').mockResolvedValueOnce({});
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.quotes = [
                {
                    carrier: {
                        name: 'carrier',
                    },
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            await page.waitForChanges();
            expect(page.rootInstance).toBeTruthy();
            expect(page.body.querySelectorAll('bp-sdk-quote-request').length).toBe(0);
            expect(page.body.querySelector('bp-sdk-external-quote-request-container')).toBeTruthy();
            whenDefinedMock.mockRestore();
        });
    });
    describe('disconnectedCallback', () => {
        it('makes expected calls', async () => {
            const page = await setupPage();
            await page.waitForChanges();
            const instance = setupInstance(page);
            instance.storeUnsubscribe = jest.fn();
            instance.disconnectedCallback();
            expect(instance.storeUnsubscribe).toHaveBeenCalledTimes(1);
        });
    });
    describe('onQuotesResourceStateChange', () => {
        it('should set isReady to true if state is Loaded', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.isReady = false;
            instance.quotesResourceState = LoadingStates.Loaded;
            expect(instance.isReady).toBe(true);
        });
        it('should call setTimeout when transitioning to Loading state', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.resetAllMocks();
            instance.onQuotesResourceStateChange(LoadingStates.Loading, LoadingStates.NotLoaded);
            expect(setTimeout).toHaveBeenCalledTimes(1);
            expect(setTimeout).toHaveBeenCalledWith(instance.handleQuoteTimeout, instance.quoteTimeout * 1000);
        });
        it('should not call setTimeout when oldResources are not defined', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            jest.resetAllMocks();
            instance.onQuotesResourceStateChange(LoadingStates.Loading, undefined);
            expect(setTimeout).not.toHaveBeenCalled();
        });
        it('should call handleQuoteTimeout after 90 seconds', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.handleQuoteTimeout = jest.fn();
            expect(instance.handleQuoteTimeout).not.toHaveBeenCalled();
            jest.clearAllTimers(); // Clear the timers that get added by setting up the component first
            instance.onQuotesResourceStateChange(LoadingStates.Loading, LoadingStates.NotLoaded);
            jest.runAllTimers();
            expect(instance.handleQuoteTimeout).toHaveBeenCalledTimes(1);
        });
    });
    describe('handleQuoteTimeout', () => {
        it('should call timeoutQuoteState', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            expect(instance.timeoutQuoteState).not.toHaveBeenCalled();
            instance.handleQuoteTimeout();
            expect(instance.timeoutQuoteState).toHaveBeenCalled();
        });
    });
    describe('handleBind', () => {
        it('completed quotes', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const quoteId = '0';
            const appFormId = '1';
            const afterResponse = () => { };
            await page.waitForChanges();
            instance.handleBind(quoteId, appFormId, afterResponse);
            expect(instance.bindQuoteRequest).toHaveBeenCalledTimes(1);
            expect(instance.bindQuoteRequest).toHaveBeenCalledWith({
                quoteId,
                appFormId,
                afterResponse,
                config: instance.config,
            });
        });
    });
    describe('handleQuoteActions', () => {
        it(`should render bp-sdk-quote-payment on 'pay' action`, async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const quoteAction = { name: 'Make a payment', value: 'pay' };
            instance.quotes = [
                {
                    actions: [quoteAction],
                    carrier: {
                        name: 'carrier',
                        id: '123',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            instance.appFormState = ApplicationFormStates.Completed;
            expect(instance.showQuotePayment).toBeFalsy();
            expect(instance.isReady).toBeTruthy();
            instance.handleQuoteActionBind(quoteAction, { id: '123', application_form_id: '456' });
            await page.waitForChanges();
            expect(instance.showQuotePayment).toBeTruthy();
            expect(page.root.querySelector('bp-sdk-quote-payment')).toBeTruthy();
        });
    });
    describe('mapStateToProps', () => {
        it('returns an object containing all the expected keys', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const result = instance.mapStateToProps(fakeStore);
            expect(result).toHaveProperty('quotes');
            expect(result).toHaveProperty('appFormState');
            expect(result).toHaveProperty('config');
            expect(result).toHaveProperty('carriersProducts');
            expect(result).toHaveProperty('carriersProductsResourceState');
            expect(result).toHaveProperty('applicationFormResourceState');
            expect(result).toHaveProperty('quotesResourceState');
            expect(result).toHaveProperty('configOptions');
        });
    });
    describe('showAllQuotes', () => {
        it('default state', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.configOptions = Object.assign({}, instance.configOptions);
            instance.appFormState = ApplicationFormStates.Completed;
            instance.showAllQuotes = false;
            instance.isReady = true;
            instance.quotes = [
                {
                    order: 10,
                    carrier: {
                        name: 'carrier1',
                    },
                    request_status: QuoteRequestRequestTypes.ineligible,
                },
                {
                    order: 11,
                    carrier: {
                        name: 'carrier2',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-quote-request').length).toEqual(1);
        });
        it('ineligible showAll', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.configOptions = Object.assign({}, instance.configOptions);
            instance.appFormState = ApplicationFormStates.Completed;
            instance.showAllQuotes = true;
            instance.isReady = true;
            instance.quotes = [
                {
                    order: 10,
                    carrier: {
                        name: 'carrier1',
                    },
                    request_status: QuoteRequestRequestTypes.ineligible,
                },
                {
                    order: 11,
                    carrier: {
                        name: 'carrier2',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-quote-request').length).toEqual(2);
        });
    });
    describe('sorting', () => {
        it('default sorts online quotes', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            instance.quotes = [
                {
                    order: 10,
                    carrier: {
                        name: 'carrier1',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
                {
                    order: 5,
                    carrier: {
                        name: 'carrier2',
                    },
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-quote-request')[0].carrier.name).toEqual(instance.quotes[1].carrier.name);
            expect(page.body.querySelectorAll('bp-sdk-quote-request')[1].carrier.name).toEqual(instance.quotes[0].carrier.name);
        });
        it('custom sorts online quotes when prop is passed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            instance.quotesSortFn = (a, b) => {
                return Number(a.annual_price) - Number(b.annual_price);
            };
            instance.quotes = [
                {
                    order: 5,
                    carrier: {
                        name: 'higher_price',
                    },
                    annual_price: '500',
                    request_status: QuoteRequestRequestTypes.completed,
                },
                {
                    order: 10,
                    carrier: {
                        name: 'lower_price',
                    },
                    annual_price: '100',
                    request_status: QuoteRequestRequestTypes.completed,
                },
            ];
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-quote-request')[0].carrier.name).toEqual(instance.quotes[1].carrier.name);
            expect(page.body.querySelectorAll('bp-sdk-quote-request')[1].carrier.name).toEqual(instance.quotes[0].carrier.name);
        });
        it('custom sorts offline quotes when prop is passed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.appFormState = ApplicationFormStates.Completed;
            instance.isReady = true;
            instance.configOptions = Object.assign(Object.assign({}, instance.configOptions), { renderOfflineQuotes: true });
            instance.offlineQuotesSortFn = (a, b) => {
                return a.carrier.name > b.carrier.name ? 1 : -1; // Sort alphabetically by carrier name
            };
            instance.carriersProducts = [
                {
                    product: {},
                    carrier: {
                        name: 'DEF',
                        online: false,
                    },
                },
                {
                    product: {},
                    carrier: {
                        name: 'ABC',
                        online: false,
                    },
                },
            ];
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-offline-quote')[0].carrier.name).toEqual(instance.carriersProducts[1].carrier.name);
            expect(page.body.querySelectorAll('bp-sdk-offline-quote')[1].carrier.name).toEqual(instance.carriersProducts[0].carrier.name);
        });
    });
});
