import React from 'react';
import { act } from 'react-dom/test-utils';

import '../../../../__mocks__/matchMedia';
// eslint-disable-next-line react/prop-types
jest.mock('react-file-drop', () => props => <div id="react-file-drop-mock">{props.children}</div>);
let mockedManager;
jest.mock('../DesignerProductPreviewManager', () => {
    mockedManager = {
        init: jest.fn(),
        useImage: jest.fn(),
    };
    return {
        createDesignerProductPreviewManager: () => mockedManager,
    };
});
jest.mock('../../../Reducers/ImageGallery/Actions');
import { editImage } from '../../../Reducers/ImageGallery/Actions';

import { render, mount } from 'enzyme/build';
import { createStoreProvider } from '../../../../Utils/Test/createStoreProvider';
import { ConnectedDesignerProductPreviewScreen } from '../Screen';
import MainButton from '../../../../Shared/Components/MainButton';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import ServiceLocator from '../../../ServiceLocator';
import { RECEIVE_IMAGE_UPLOAD_DATA } from '../../../Reducers/ImageGallery/Actions';

describe('Screens/DesignerProductPreview/Screen', () => {
    it('renders the initial image upload step', () => {
        const { StoreProvider } = createStoreProvider();
        const tree = render(
            <StoreProvider>
                <ConnectedDesignerProductPreviewScreen />
            </StoreProvider>
        );
        expect(tree).toMatchSnapshot();
    });
    describe('complete feature test', () => {
        const { StoreProvider, store } = createStoreProvider();
        const imageUrl =
            'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';

        const editImagePromise = Promise.resolve();
        editImage.mockImplementation(() => (editParams, imageData) => {
            store.dispatch({
                type: RECEIVE_IMAGE_UPLOAD_DATA,
                imageData: {
                    fileName: 'testFile.jpg',
                    preview: {
                        url: imageUrl,
                    },
                    ...imageData,
                },
            });
            return editImagePromise;
        });

        const mockDesignerSrvc = new (class DesignerService {
            static serviceName = 'DesignerService';
            uploadFile = jest.fn(() => {
                store.dispatch({
                    type: RECEIVE_IMAGE_UPLOAD_DATA,
                    imageData: {
                        fileName: 'testFile.jpg',
                        preview: {
                            url: imageUrl,
                        },
                    },
                });
            });
        })();
        ServiceLocator.provide(mockDesignerSrvc);

        const wrapper = mount(
            <StoreProvider>
                <ConnectedDesignerProductPreviewScreen />
            </StoreProvider>
        );

        // helper functions to get controls easily
        const getButtonByText = text => wrapper.find(MainButton).filterWhere(item => item.text() === text);
        const getFormControlByLabel = text =>
            wrapper.find(FormControlLabel).filterWhere(item => item.text() === text);

        describe('file upload step', () => {
            test('continue button is disabled by default', () => {
                expect(getButtonByText('fileUpload.continue').props().disabled).toBe(true);
            });
            test('after selecting a file: the file name is shown, the continue button is enabled', () => {
                const fileInput = wrapper.find('input[type="file"]');
                fileInput.simulate('change', { target: { files: [{ name: 'testFile.jpg', size: 20000 }] } });
                // the file name is shown
                expect(wrapper.text()).toContain('testFile.jpg');
                // the continue button is enabled
                expect(getButtonByText('fileUpload.continue').props().disabled).toBe(false);
            });
            test('when first clicking "Next" button the ownership error message is shown', () => {
                getButtonByText('fileUpload.continue')
                    .find('button')
                    .simulate('click');
                expect(wrapper.text()).toContain('fileUpload.imageOwnershipError');
            });
            test('checking the ownership confirmation, the error message is removed', () => {
                getFormControlByLabel('fileUpload.confirmImageOwnership')
                    .find('input')
                    .simulate('change', { target: { checked: true } });
                expect(wrapper.text()).not.toContain('fileUpload.imageOwnershipError');
            });
            test('clicking the "Next" button uploads the file', async () => {
                await act(async () =>
                    getButtonByText('fileUpload.continue')
                        .find('button')
                        .simulate('click')
                );
                expect(mockDesignerSrvc.uploadFile).toBeCalledWith({ name: 'testFile.jpg', size: 20000 });
                // due to async state changes in deeper levels components (eg. ImageUpload) the wrapper should be updated
                wrapper.update();
            });
        });

        describe('background removal step', () => {
            test('ImageColorPicker is shown', () => {
                expect(wrapper.find('ImageColorPicker')).toHaveLength(1);
            });
            test('background removal is not active by default', () => {
                expect(
                    getFormControlByLabel('fileUpload.removeBackground')
                        .find('input')
                        .props().checked
                ).toBe(false);
            });
            test('toggling remove background calls editImage with the "replace" command initially', () => {
                getFormControlByLabel('fileUpload.removeBackground')
                    .find('input')
                    .simulate('change', { target: { checked: true } });
                expect(editImage).toHaveBeenNthCalledWith(
                    1,
                    expect.objectContaining({
                        fileName: 'testFile.jpg',
                        operations: [
                            {
                                identifier: 'clipping',
                                config: {
                                    command: 'replace',
                                    backgroundColor: '#ffffff',
                                },
                            },
                        ],
                    }),
                    expect.anything()
                );
            });
            test('the "replace" mode is active initially when toggling background removal', () => {
                expect(
                    getFormControlByLabel('fileUpload.removeBackgroundEverywhere')
                        .find('input')
                        .props().checked
                ).toBe(true);
            });
            test('switching to "flood" mode calls editImage with the "flood" command', () => {
                getFormControlByLabel('fileUpload.removeBackgroundFromBorder')
                    .find('input')
                    .simulate('change', { target: { checked: true, value: 'flood' } });
                expect(editImage).toHaveBeenNthCalledWith(
                    2,
                    expect.objectContaining({
                        fileName: 'testFile.jpg',
                        operations: [
                            {
                                identifier: 'clipping',
                                config: {
                                    command: 'flood',
                                    backgroundColor: '#ffffff',
                                },
                            },
                        ],
                    }),
                    expect.anything()
                );
            });
            test('change event of ImageColorPicker triggers the editImage call with the selected backgroundColor', async () => {
                await act(async () =>
                    wrapper
                        .find('ImageColorPicker')
                        .props()
                        .onChange({ hex: '#ff0000' })
                );
                expect(editImage).toHaveBeenNthCalledWith(
                    3,
                    expect.objectContaining({
                        fileName: 'testFile.jpg',
                        operations: [
                            {
                                identifier: 'clipping',
                                config: {
                                    command: 'flood',
                                    backgroundColor: '#ff0000',
                                },
                            },
                        ],
                    }),
                    expect.anything()
                );
            });
            test('clicking the "Next" button calls the useImage function', async () => {
                const continueButton = getButtonByText('fileUpload.continue').find('button');
                expect(continueButton.props().disabled).toBe(false);
                await act(async () => continueButton.simulate('click'));
                expect(mockedManager.useImage).toBeCalled();
            });
            test('clicking the "Change image" button takes back to the image upload state', () => {
                getButtonByText('fileUpload.changeImage')
                    .find('button')
                    .simulate('click');
                expect(wrapper.find('input[type="file"]')).toHaveLength(1);
            });
        });
    });
});
