import { setConf } from '../../../configuration';
import imageGalleryReducer from '../Reducer';
import {
    DISMISS_ERROR,
    RECEIVE_GALLERY,
    RECEIVE_GALLERY_TAGS,
    RECEIVE_IMAGE_UPLOAD_DATA,
    SELECT_GALLERY_TAG,
    SELECT_GALLERY_TAGS,
    ADD_IMAGES_FROM_DESIGN_AREA,
    ADD_GALLERY_IMAGE_TO_USER_IMAGES,
    SET_SELECTED_IMAGE,
    UPDATE_IMAGE,
} from '../Actions';

describe('Reducers/ImageGallery/Reducer', () => {
    let initialState;
    beforeEach(() => {
        initialState = imageGalleryReducer();
    });

    it('sets the gallery data correctly on RECEIVE_GALLERY action', () => {
        const imageList = [
            {
                previewUrl: 'image1.png',
            },
            {
                previewUrl: 'image2.png',
            },
        ];
        expect(
            imageGalleryReducer(initialState, {
                type: RECEIVE_GALLERY,
                data: imageList,
            })
        ).toEqual({
            ...initialState,
            gallery: imageList,
        });
    });
    it('sets the tags correctly on RECEIVE_GALLERY_TAGS action', () => {
        const tagList = [
            {
                title: 'tag1',
            },
            {
                title: 'tag2',
            },
        ];
        expect(
            imageGalleryReducer(initialState, {
                type: RECEIVE_GALLERY_TAGS,
                data: tagList,
            })
        ).toEqual({
            ...initialState,
            tags: tagList,
        });
    });
    it('selects the gallery tag correctly on SELECT_GALLERY_TAG action', () => {
        const selectedTag = {
            title: 'tag1',
        };
        expect(
            imageGalleryReducer(initialState, {
                type: SELECT_GALLERY_TAG,
                tag: selectedTag,
            })
        ).toEqual({
            ...initialState,
            selectedTag,
        });
    });
    it('selects the gallery tags correctly on SELECT_GALLERY_TAGS action', () => {
        const selectedTags = [
            {
                title: 'tag1',
                checked: true,
            },
            {
                title: 'tag2',
                checked: true,
            },
        ];
        expect(
            imageGalleryReducer(initialState, {
                type: SELECT_GALLERY_TAGS,
                tags: selectedTags,
            })
        ).toEqual({
            ...initialState,
            selectedTags,
        });
    });
    it('adds the image data to the selectedImage on RECEIVE_IMAGE_UPLOAD_DATA action', () => {
        const imageData = {
            fileName: 'userimage1',
        };
        const nextState = imageGalleryReducer(initialState, {
            type: RECEIVE_IMAGE_UPLOAD_DATA,
            data: imageData,
        });
        expect(nextState.selectedImage.fileName).toBe('userimage1');
    });
    it('does not add the image to the userImages even if the createCopy flag is set on RECEIVE_IMAGE_UPLOAD_DATA action', () => {
        const imageData = {
            fileName: 'userimage1',
        };
        const nextState = imageGalleryReducer(initialState, {
            type: RECEIVE_IMAGE_UPLOAD_DATA,
            data: imageData,
            createCopy: true,
        });
        expect(nextState.userImages.length).toBe(0);
    });
    it('a new image identifier is created if the createCopy flag is true on RECEIVE_IMAGE_UPLOAD_DATA action', () => {
        const imageData = {
            fileName: 'userimage1',
        };
        const state1 = imageGalleryReducer(initialState, {
            type: RECEIVE_IMAGE_UPLOAD_DATA,
            data: imageData,
        });
        const state2 = imageGalleryReducer(initialState, {
            type: RECEIVE_IMAGE_UPLOAD_DATA,
            data: imageData,
            createCopy: true,
        });
        expect(state2.selectedImage.identifier).not.toBe(state1.selectedImage.identifier);
    });
    it('the copy is added to the userImages if the immediateCommit flag is true on RECEIVE_IMAGE_UPLOAD_DATA action', () => {
        const imageData = {
            fileName: 'userimage1',
        };
        const state = imageGalleryReducer(initialState, {
            type: RECEIVE_IMAGE_UPLOAD_DATA,
            data: imageData,
            createCopy: true,
            immediateCommit: true,
        });
        expect(state.userImages[0].identifier).toBe(state.selectedImage.identifier);
    });
    it('sets the lastErrorCode correctly if the upload was not successful on RECEIVE_IMAGE_UPLOAD_DATA action', () => {
        expect(
            imageGalleryReducer(initialState, {
                type: RECEIVE_IMAGE_UPLOAD_DATA,
                data: {
                    code: 'wrong_file',
                },
                response: {
                    status: 400,
                },
            })
        ).toEqual({
            ...initialState,
            lastErrorCode: 'wrong_file',
        });
    });
    it('copies the operations and the displayColorPreview property from the previous selected image to the current one', () => {
        const id = 'thisIsaUniqueId';
        const operations = {
            vectorizeColorsMap: {
                '#000000': {
                    identifier: '{"color":"red","palette":"default"}',
                    value: '#FF0000',
                },
            },
            vectorizeOriginalColorsMap: {
                '#000000': {
                    identifier: '{"color":"black","palette":"default"}',
                    value: '#000000',
                },
            },
        };
        const displayColorPreview = true;

        const state = imageGalleryReducer(
            {
                ...initialState,
                selectedImage: {
                    identifier: id,
                    operations,
                    displayColorPreview,
                },
            },
            {
                type: RECEIVE_IMAGE_UPLOAD_DATA,
                data: {
                    identifier: id,
                },
            }
        );

        expect(state.selectedImage.operations).toEqual(operations);
        expect(state.selectedImage.displayColorPreview).toBe(displayColorPreview);
    });
    it('removes the lastErrorCode on DISMISS_ERROR action', () => {
        const stateWithError = {
            ...initialState,
            lastErrorCode: 'wrong_file',
        };
        expect(
            imageGalleryReducer(stateWithError, {
                type: DISMISS_ERROR,
            })
        ).toEqual({
            ...initialState,
            lastErrorCode: null,
        });
    });

    it('ADD_IMAGES_FROM_DESIGN_AREA adds images from the action data to userImages', () => {
        const stateWithUserImages = {
            ...initialState,
            userImages: [
                {
                    fileName: 'someFile.jpg',
                    preview: {
                        url: 'https://example.com/123.jpg',
                    },
                },
            ],
        };
        const action = {
            type: ADD_IMAGES_FROM_DESIGN_AREA,
            data: [
                {
                    fileName: '9c1330f774e4dada3c1bc8e2535143c3',
                    preview: {
                        url: '/img/uploads/designer/preview/9c1330f774e4dada3c1bc8e2535143c3.svg',
                    },
                },
            ],
        };
        expect(imageGalleryReducer(stateWithUserImages, action)).toEqual({
            ...stateWithUserImages,
            userImages: [...stateWithUserImages.userImages, ...action.data],
        });
    });

    it('ADD_GALLERY_IMAGE_TO_USER_IMAGES adds image from the action data to selectedImage for editing', () => {
        const imageUrl = 'fakeImageUrl';
        const thumbUrl = 'fakeThumbUrl';
        const fileName = 'fakeFileName';
        const vectorizeColorsMap = {
            fakeColor: '#000000',
        };
        const compatibilityInfoHash = {
            colorPalettes: ['palette_1'],
            vectorsRequired: true,
            maxColorAmount: 4,
        };

        const action = {
            type: ADD_GALLERY_IMAGE_TO_USER_IMAGES,
            imageUrl,
            thumbUrl,
            fileName,
            vectorizeColorsMap,
            compatibilityInfoHash,
        };

        const expectedResult = {
            fileName,
            gallery: true,
            message: null,
            operations: {
                vectorizeColorsMap,
            },
            original: {
                format: 'SVG',
                height: 290,
                mimeType: 'image/svg+xml',
                url: null,
                width: 290,
            },
            isPlaceHolderImage: false,
            originalFileName: imageUrl,
            preview: {
                format: 'SVG',
                height: 290,
                mimeType: 'image/svg+xml',
                url: imageUrl,
                width: 290,
            },
            thumbnail: {
                format: 'PNG',
                height: 160,
                mimeType: 'image/png',
                url: thumbUrl,
                width: 160,
            },
            compatibilityInfoHash,
        };

        const result = imageGalleryReducer(initialState, action).selectedImage;

        // Omit random generated identifiers by comparing
        delete result.identifier;

        expect(result).toEqual(expectedResult);
    });

    it('SET_SELECTED_IMAGE with identifier selects the correct image', () => {
        const stateWithUserImages = {
            ...initialState,
            userImages: [{ identifier: 'id_1' }, { identifier: 'id_2' }, { identifier: 'id_3' }],
        };
        const action = {
            type: SET_SELECTED_IMAGE,
            identifier: 'id_2',
        };
        expect(imageGalleryReducer(stateWithUserImages, action).selectedImage).toBe(
            stateWithUserImages.userImages[1]
        );
    });

    test('UPDATE_IMAGE patches the image data correctly', () => {
        const state = {
            ...initialState,
            selectedImage: {
                identifier: 'image1',
                propToReplace: 42,
            },
        };
        const action = {
            type: UPDATE_IMAGE,
            imageUsageInfo: { designAreas: 1 },
            imageDataPatch: {
                propToReplace: 24,
            },
        };
        expect(imageGalleryReducer(state, action).selectedImage.propToReplace).toBe(24);
    });

    test('UPDATE_IMAGE patches the image data correctly and adds it to the user images if the immediateCommit is true', () => {
        const state = {
            ...initialState,
            selectedImage: {
                identifier: 'image1',
                propToReplace: 42,
            },
        };
        const action = {
            type: UPDATE_IMAGE,
            imageUsageInfo: { designAreas: 1 },
            imageDataPatch: {
                propToReplace: 24,
            },
            immediateCommit: true,
            identifier: 'image1',
        };
        const nextState = imageGalleryReducer(state, action);
        expect(nextState.selectedImage.propToReplace).toBe(24);
        expect(nextState.selectedImage.identifier).toBe('image1');
        expect(nextState.userImages[0]).toBe(nextState.selectedImage);
    });

    test('UPDATE_IMAGE creates a new identifier if the image is "hard-modified" and used in more design areas', () => {
        const state = {
            ...initialState,
            selectedImage: {
                identifier: 'image1',
                displayColorPreview: false,
                operations: {
                    vectorize: false,
                },
            },
        };
        const action = {
            type: UPDATE_IMAGE,
            imageUsageInfo: { designAreas: 2 },
            imageDataPatch: {
                operations: {
                    vectorize: true,
                },
            },
            identifier: 'image1',
        };
        const nextState = imageGalleryReducer(state, action);
        expect(nextState.selectedImage.operations.vectorize).toBe(true);
        expect(nextState.selectedImage.identifier).not.toBe('image1');
    });

    test(
        'UPDATE_IMAGE does not create a new identifier if the image is used in more design areas ' +
            'but not "hard-modified"',
        () => {
            const state = {
                ...initialState,
                selectedImage: {
                    identifier: 'image1',
                    displayColorPreview: true,
                },
            };
            const action = {
                type: UPDATE_IMAGE,
                imageUsageInfo: { designAreas: 2 },
                imageDataPatch: {
                    displayColorPreview: false,
                },
                identifier: 'image1',
            };
            const nextState = imageGalleryReducer(state, action);
            expect(nextState.selectedImage.displayColorPreview).toBe(false);
            expect(nextState.selectedImage.identifier).toBe('image1');
        }
    );

    describe('imageColorsWereEdited prop is calculated correctly', () => {
        test('true if the colors are modified', () => {
            const state = {
                ...initialState,
                selectedImage: {
                    identifier: 'image1',
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                },
            };
            const action = {
                type: UPDATE_IMAGE,
                imageUsageInfo: { designAreas: 1 },
                imageDataPatch: {
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"white","palette":"default"}',
                                value: '#ffffff',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                },
                identifier: 'image1',
            };
            const nextState = imageGalleryReducer(state, action);
            expect(nextState.selectedImage.imageColorsWereEdited).toBe(true);
        });
        test('false if the colors are the same', () => {
            const state = {
                ...initialState,
                selectedImage: {
                    identifier: 'image1',
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                },
            };
            const action = {
                type: UPDATE_IMAGE,
                imageUsageInfo: { designAreas: 1 },
                imageDataPatch: {
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                },
                identifier: 'image1',
            };
            const nextState = imageGalleryReducer(state, action);
            expect(nextState.selectedImage.imageColorsWereEdited).toBe(false);
        });
    });

    describe('colorPreviewEnabled prop is calculated correctly', () => {
        test('true if the colors are modified', () => {
            const state = {
                ...initialState,
                selectedImage: {
                    identifier: 'image1',
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                },
            };
            const action = {
                type: UPDATE_IMAGE,
                imageUsageInfo: { designAreas: 1 },
                imageDataPatch: {
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"white","palette":"default"}',
                                value: '#ffffff',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                },
                identifier: 'image1',
            };
            const nextState = imageGalleryReducer(state, action);
            expect(nextState.selectedImage.colorPreviewEnabled).toBe(true);
        });
        test('false if the colors are modified but close to each other', () => {
            const state = {
                ...initialState,
                selectedImage: {
                    identifier: 'image1',
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                },
            };
            const action = {
                type: UPDATE_IMAGE,
                imageUsageInfo: { designAreas: 1 },
                imageDataPatch: {
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"dark-grey","palette":"default"}',
                                value: '#141414',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                },
                identifier: 'image1',
            };
            const nextState = imageGalleryReducer(state, action);
            expect(nextState.selectedImage.colorPreviewEnabled).toBe(false);
        });
        test('true if the colors are not modified but color preview is required (eg. for embroidery)', () => {
            const state = {
                ...initialState,
                selectedImage: {
                    identifier: 'image1',
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                },
            };
            const action = {
                type: UPDATE_IMAGE,
                imageUsageInfo: { designAreas: 1 },
                imageDataPatch: {
                    operations: {
                        vectorizeColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                        vectorizeOriginalColorsMap: {
                            '#000000': {
                                identifier: '{"color":"black","palette":"default"}',
                                value: '#000000',
                            },
                        },
                    },
                    colorPreviewRequired: true,
                },
                identifier: 'image1',
            };
            const nextState = imageGalleryReducer(state, action);
            expect(nextState.selectedImage.colorPreviewEnabled).toBe(true);
        });
    });

    describe('displayColorPreview is set to the value of autoPreviewVectorization (conf) if the colorPreviewEnabled changes to true from false', () => {
        test('default conf value is true', () => {
            const state = {
                ...initialState,
                selectedImage: {
                    identifier: 'image1',
                    displayColorPreview: false,
                },
            };
            const action = {
                type: UPDATE_IMAGE,
                imageUsageInfo: { designAreas: 1 },
                imageDataPatch: {
                    colorPreviewRequired: true,
                },
                identifier: 'image1',
            };
            const nextState = imageGalleryReducer(state, action);
            expect(nextState.selectedImage.displayColorPreview).toBe(true);
        });
        test('conf value is false', () => {
            setConf('autoPreviewVectorization', false);
            const state = {
                ...initialState,
                selectedImage: {
                    identifier: 'image1',
                    displayColorPreview: true,
                },
            };
            const action = {
                type: UPDATE_IMAGE,
                imageUsageInfo: { designAreas: 1 },
                imageDataPatch: {
                    colorPreviewRequired: true,
                },
                identifier: 'image1',
            };
            const nextState = imageGalleryReducer(state, action);
            expect(nextState.selectedImage.displayColorPreview).toBe(false);
        });
    });

    test('SET_SELECTED_IMAGE sets the image data directly if provided by the imageData prop', () => {
        const imageData = {
            preview: {
                url: 'myImage.png',
            },
        };
        const action = {
            type: SET_SELECTED_IMAGE,
            imageData,
        };
        expect(imageGalleryReducer(initialState, action).selectedImage).toBe(imageData);
    });
});
