import AmountPrice, {
    createAmountPropsFromState,
    createPricePropsFromState,
    showProductVariantsForItem,
} from './index';
import mountWithState from 'Utils/Test/mountWithState';
import ServiceLocator from 'App/ServiceLocator';

describe('Screens/Configurator/Containers/AmountPrice', () => {
    // mock state data
    const calculation = {
        totalFormatted: '68,00 €',
        positions: [
            {
                calculationTypeIdentifier: 'test_calc_id',
                selectableByUser: true,
                title: 'Test calc',
                priceFormatted: '9,89 €',
            },
            {
                calculationTypeIdentifier: 'other_test_calc_id',
                selectableByUser: false,
                title: 'Other test calc',
                priceFormatted: '2,00 €',
            },
        ],
    };
    const configuration = {
        customdata: {
            userSelectedCalculation: {
                test_calc_id: true,
            },
            selectedAmounts: {
                test_identifier: 4,
                other_test_identifier: 9,
            },
        },
    };
    const configurationMode = {
        availableModes: {
            creator: true,
            designer: true,
        },
    };

    const ui = {
        visibilityMap: {
            globalLoader: false,
            addToCartPopUpLoader: false,
        },
    };

    // expected results
    const priceListResult = [
        {
            key: 'test_calc_id',
            selectable: true,
            selected: true,
            label: 'Test calc',
            price: '9,89 €',
        },
        {
            key: 'other_test_calc_id',
            selectable: false,
            selected: false,
            label: 'Other test calc',
            price: '2,00 €',
        },
    ];
    const priceFormattedResult = '68,00 €';
    const amountResult = 4 + 9;

    test('createPricePropsFromState creates the priceList and priceFormatted props from the state', () => {
        // it returns an object that contains priceList and priceFormatted props
        expect(createPricePropsFromState({ calculation, configuration })).toEqual(
            expect.objectContaining({
                priceList: priceListResult,
                priceFormatted: priceFormattedResult,
            })
        );
    });
    test('createAmountPropsFromState creates the amount prop the state', () => {
        // it returns an object that contains the amount prop
        expect(createAmountPropsFromState({ configuration })).toEqual({
            amount: amountResult,
        });
    });
    test('showProductVariantsForItem tells if the variants should be shown or not from the state', () => {
        // it returns a boolean value
        expect(showProductVariantsForItem({})).toBe(false);
        expect(
            showProductVariantsForItem({
                configuration: {
                    item: {
                        itemGroup: {
                            children: [{}, {}],
                        },
                    },
                },
            })
        ).toBe(true);
    });

    // integration tests
    describe('Connected component', () => {
        test('the connected component gets the correct props for empty initial state', () => {
            const { wrapper } = mountWithState(
                AmountPrice,
                {
                    configurator: {
                        configuration: {},
                    },
                    configurationMode,
                    ui: {
                        visibilityMap: {},
                    },
                },
                { width: 'lg' }
            );
            const props = wrapper.find('AmountPrice').props();
            expect(props).toEqual(
                expect.objectContaining({
                    priceList: [],
                    priceFormatted: '',
                    amount: 0,
                    showProductVariants: true,
                })
            );
        });
        test('the connected component gets the correct props from the filled state', () => {
            const { wrapper } = mountWithState(
                AmountPrice,
                {
                    configurator: {
                        configuration,
                        calculation,
                    },
                    configurationMode,
                    ui,
                },
                { width: 'lg' }
            );
            const props = wrapper.find('AmountPrice').props();
            expect(props).toEqual(
                expect.objectContaining({
                    priceList: priceListResult,
                    priceFormatted: priceFormattedResult,
                    amount: amountResult,
                    showProductVariants: true,
                })
            );
        });
        test('the connected components get the correct showProductVariants prop', () => {
            const { wrapper } = mountWithState(
                AmountPrice,
                {
                    configurator: {
                        configuration: {
                            item: {
                                itemGroup: {
                                    children: [{}, {}],
                                },
                            },
                        },
                        calculation,
                    },
                    configurationMode,
                    ui,
                },
                { width: 'lg' }
            );
            const props = wrapper.find('AmountPrice').props();
            expect(props).toEqual(
                expect.objectContaining({
                    showProductVariants: true,
                })
            );
        });
        // note: we should test only that the service functions are called correctly
        // since their implementation (calling dispatch with the correct action) is already tested
        test(
            'the onSelectableChanged prop calls the ConfiguratorService.setSelectedCalculation ' +
                'with the correct args',
            () => {
                const configuratorSrvc = new (class {
                    static serviceName = 'ConfiguratorService';
                    setSelectedCalculation = jest.fn();
                })();
                ServiceLocator.provide(configuratorSrvc);
                const { wrapper } = mountWithState(
                    AmountPrice,
                    {
                        configurator: { configuration: { item: {} } },
                        configurationMode,
                        ui,
                    },
                    { width: 'lg' }
                );
                const props = wrapper.find('AmountPrice').props();
                props.onSelectableChanged('test_calc_id', true);
                expect(configuratorSrvc.setSelectedCalculation).toBeCalledWith('test_calc_id', true);
                props.onSelectableChanged('test_calc_id', false);
                expect(configuratorSrvc.setSelectedCalculation).toBeCalledWith('test_calc_id', false);
            }
        );
        test(
            'the onChangeAmount prop calls the ConfiguratorService.setSelectedAmount ' +
                'with the correct args',
            () => {
                const configuratorSrvc = new (class {
                    static serviceName = 'ConfiguratorService';
                    setSelectedAmount = jest.fn();
                })();
                ServiceLocator.provide(configuratorSrvc);
                const { wrapper } = mountWithState(
                    AmountPrice,
                    {
                        configurator: { configuration: { item: {} } },
                        configurationMode,
                        ui,
                    },
                    { width: 'lg' }
                );
                const props = wrapper.find('AmountPrice').props();
                props.onChangeAmount(7);
                expect(configuratorSrvc.setSelectedAmount).toBeCalledWith(false, 7);
            }
        );
        test('onAddToBasket calls the right service', async () => {
            const interactionSrvc = new (class {
                static serviceName = 'InteractionService';
                addToCart = jest.fn();
            })();

            ServiceLocator.provide(interactionSrvc);

            const { wrapper } = mountWithState(
                AmountPrice,
                {
                    configurator: { configuration: { item: {} } },
                    configurationMode,
                    ui,
                },
                { width: 'lg' }
            );
            const props = wrapper.find('AmountPrice').props();

            await props.onAddToBasket();

            expect(interactionSrvc.addToCart.mock.calls.length).toBe(1);
        });
    });
});
