import get from 'lodash/get';
import first from 'lodash/first';
import find from 'lodash/find';
import findKey from 'lodash/findKey';
import uniq from 'lodash/uniq';
import uniqWith from 'lodash/uniqWith';
import isEmpty from 'lodash/isEmpty';
import replace from 'lodash/replace';
import isObject from 'lodash/isObject';
import uniqBy from 'lodash/uniqBy';
import cloneDeep from 'lodash/cloneDeep';
import intersectionBy from 'lodash/intersectionBy';
import isEqual from 'lodash/isEqual';
import values from 'lodash/values';
import createSelector from 'Utils/Function/createSelector';
import memoize from 'Utils/Function/memoize';
import { getConf } from '../../configuration';
import { getMissingColorPalettesColors } from '../../Services/DesignDataService';
import { getConfigurator, getSelectedVariantIdentifier } from '../Configurator/Selectors';
import { compareDesignAreasBySize } from '../DesignView/Transformers';
import { isImageCompatible } from '../ImageGallery/Selectors';
import { recalculateSingleDesignArea } from './Transformers';
import { CONFIGURATION_NOT_FOUND_ERROR } from '../UI/Actions';
export * from './MaskSelectors';

export function getDesignProductionMethods(state) {
    return get(state, 'designArea.selectedDesignArea.designProductionMethods');
}

export function getDesignDataByDesignAreaIdentifier({ configurator }, designAreaIdentifier) {
    const { configuration } = configurator;
    return get(configuration, `designdata.${designAreaIdentifier}`, {});
}

export function getDesignDataColorAmounts({ configurator }) {
    const { configuration } = configurator;
    const designdata = get(configuration, 'designdata', {});
    const colorAmounts = {};
    for (const key in designdata) {
        if (!designdata.hasOwnProperty(key)) {
            continue;
        }

        colorAmounts[key] = designdata[key].colorAmount;
    }
    return colorAmounts;
}

export function getUsedColorsForDesignAreas(state) {
    const designdata = get(state, 'configurator.configuration.designdata', {});
    const colors = [];
    for (const key in designdata) {
        if (!designdata.hasOwnProperty(key)) {
            continue;
        }
        if (!isEmpty(designdata[key].canvasData)) {
            for (const object of designdata[key].canvasData.objects) {
                let objectColors;
                if (object.type === 'Image') {
                    objectColors = values(get(object, 'imageData.operations.vectorizeColorsMap')) || [];
                } else if (object.type === 'Text') {
                    objectColors = object.style.colors;
                }
                for (const colorObj of objectColors) {
                    const color = { ...colorObj };
                    let colorData = color.identifier;
                    try {
                        colorData = JSON.parse(color.identifier);
                    } catch (e) {
                        // eslint-disable-next-line no-console
                        console.error(`failed to parse color data: ${color.identifier}`);
                    }
                    if (isObject(colorData) && colorData.custom) {
                        continue;
                    }
                    if (isObject(colorData)) {
                        color.identifier = colorData.color;
                        color.palette = colorData.palette;
                    }
                    const isColorValueHex = isValidHex(color.value);
                    color.hex_value = replace(
                        isColorValueHex ? color.value : rgbString2hex(color.value),
                        '#',
                        ''
                    );
                    colors.push(color);
                }
            }
        }
    }
    return uniqBy(colors, 'identifier');
}

export function getAvailableColorsForDesignProductionMethod(productionMethod) {
    if (!productionMethod || typeof productionMethod !== 'object') {
        return [];
    }
    const { colorPalettes } = productionMethod;
    const colorsArray = colorPalettes.map(({ identifier, colors }) =>
        colors.map(color => ({ ...color, paletteIdentifier: identifier }))
    );
    return [].concat(...colorsArray);
}

export function getDesignDataUsedColors(state) {
    const usedColors = getUsedColorsForDesignAreas(state);
    const prodMethodColors = getAvailableColorsForDesignProductionMethod(
        getSelectedDesignProductionMethod(state)
    );
    return intersectionBy(usedColors, prodMethodColors, 'identifier');
}

export function getPreviousEditedDesignAreaIdentifier(state) {
    const {
        designArea: { previousEditedDesignArea },
    } = state;

    return previousEditedDesignArea.identifier;
}

export const getDesignAreaIdentifierToOpen = state => {
    const {
        designArea: {
            selectedDesignArea: { identifier },
        },
    } = state;
    const previousEditedDesignAreaIdentifier = getPreviousEditedDesignAreaIdentifier(state);
    const firstEditedDesignAreafromDesignData = getFirstEditedDesignAreafromDesignData(state);
    const designAreaFromSelectedDesignView = getDesignAreaFromSelectedDesignView(state);
    const defaultDesignAreaFromProductionMethod = getDefaultDesignAreaIdentifierFromProductionMethod(state);

    return (
        identifier ||
        previousEditedDesignAreaIdentifier ||
        firstEditedDesignAreafromDesignData ||
        designAreaFromSelectedDesignView ||
        defaultDesignAreaFromProductionMethod ||
        null
    );
};

export function getFirstEditedDesignAreafromDesignData(state) {
    const {
        configurator: {
            configuration: { designdata },
        },
    } = state;
    const editedDesignAreaIdentifier = findKey(
        designdata,
        ({ canvasData }) => canvasData && canvasData.objects.length > 0
    );
    return editedDesignAreaIdentifier;
}

export function getDesignDataForFilteredDesignAreas(state) {
    const {
        designArea: { filteredDesignAreas },
    } = state;
    const hasDesign = {};
    filteredDesignAreas.forEach(designArea => {
        hasDesign[designArea.identifier] =
            get(
                getDesignDataByDesignAreaIdentifier(state, designArea.identifier),
                'canvasData.objects.length',
                0
            ) > 0;
    });
    return hasDesign;
}

export function getDesignDataForSelectedDesignArea(state) {
    const selectedDesignArea = get(state, 'designArea.selectedDesignArea');
    if (!selectedDesignArea) {
        return {};
    }
    return getDesignDataByDesignAreaIdentifier(state, selectedDesignArea.identifier);
}

export function getSelectedDesignProductionMethod(state) {
    const designProductionMethods = getDesignProductionMethods(state);
    const designAreaData = getDesignDataForSelectedDesignArea(state);
    const { designProductionMethodIdentifier } = designAreaData;
    return (
        find(designProductionMethods, { identifier: designProductionMethodIdentifier }) ||
        first(designProductionMethods)
    );
}

export function isActiveBulkName(state) {
    const { designArea } = state;
    const designedAreas = get(designArea, 'filteredDesignAreas', []);
    for (const da of designedAreas) {
        if (da.designProductionMethods && da.designProductionMethods.length > 0) {
            for (const designProductionMethod of da.designProductionMethods) {
                if (designProductionMethod.allowBulkNames) {
                    return true;
                }
            }
        }
    }
    return false;
}

export function isBulkNamesSelected(configuratorState) {
    const { configuration } = configuratorState;
    const designData = get(configuration, 'designdata', {}) || {};
    for (const dd of Object.values(designData)) {
        if (dd.canvasData && dd.canvasData.objects.length > 0) {
            for (const object of dd.canvasData.objects) {
                if (object.isBulkName) {
                    return true;
                }
            }
        }
    }
    return false;
}

export function isCanvasUpdateRequired({ position }, { width, height }) {
    return position.width !== width || position.height !== height;
}

export function hasSelectedBulkName(designArea) {
    const canvasDataObjs = get(designArea, 'canvasData.objects', []);
    return canvasDataObjs.filter(obj => obj.type === 'Text' && obj.isBulkName).length > 0;
}

export function getSelectedDesignProductionMethodIdentifier(state) {
    const {
        configurator: { configuration },
        designArea: { selectedDesignArea },
    } = state;
    return get(configuration, `designdata.${selectedDesignArea.identifier}.designProductionMethodIdentifier`);
}

export function getSelectedDesignProductionMethodForDesignArea(state, designArea) {
    const { designProductionMethods } = designArea;
    const designAreaData = getDesignDataByDesignAreaIdentifier(state, designArea.identifier);
    const { designProductionMethodIdentifier } = designAreaData || {};
    return (
        find(designProductionMethods, { identifier: designProductionMethodIdentifier }) ||
        find(designProductionMethods, { isDefault: true }) ||
        first(designProductionMethods)
    );
}

export function getDesignProductionMethodByIdentifier(state, identifier) {
    const designProductionMethods = getDesignProductionMethods(state);
    return find(designProductionMethods, { identifier });
}

export function getSelectedDesignAreaProperties(state) {
    const { designArea } = state;
    const { filteredDesignAreas, selectedDesignArea } = designArea;
    if (!filteredDesignAreas || !selectedDesignArea) {
        return {};
    }

    if (!selectedDesignArea) {
        return {};
    }

    const designAreaData = getDesignDataForSelectedDesignArea(state);
    const { colorAmount } = designAreaData;
    const designProductionMethod = getSelectedDesignProductionMethod(state);
    const maxColorAmount = get(designProductionMethod, 'options.maxColorAmount', 0);
    const hasEngravingBackgroundColors = designProductionMethodHasEngravingVisualizationEffect(
        designProductionMethod
    );

    return {
        filteredDesignAreas,
        colorAmount,
        maxColorAmount,
        hasEngravingBackgroundColors,
        designProductionMethod,
        selectedDesignArea,
    };
}

export function getActiveDesignAreas(state) {
    const {
        designArea: { filteredDesignAreas },
    } = state;
    return filteredDesignAreas.reduce((obj, designArea) => {
        const designData = getDesignDataByDesignAreaIdentifier(state, designArea.identifier);
        return {
            ...obj,
            [designArea.identifier]: get(designData, 'canvasData.objects.length', 0) > 0,
        };
    }, {});
}

export function getSelectedDesignArea(state) {
    return get(state, 'designArea.selectedDesignArea');
}

export function isAnyDesignAreaSelected(state) {
    return Object.keys(getSelectedDesignArea(state)).length > 0;
}

function isIt500Error({ ui: { error } }) {
    return error && error.response && error.response.status === 500;
}

function isConfigurationNotFound({ ui: { error } }) {
    return (
        (error &&
            error.source &&
            error.response &&
            error.response.status === 404 &&
            ['loadbyitemidentifier', 'getconfigurationvariants'].indexOf(
                (error.source.url || error.source).split('/')[1]
            ) !== -1) ||
        (error && error.type === CONFIGURATION_NOT_FOUND_ERROR)
    );
}

export function isThereAFatalError(state) {
    return isIt500Error(state) || isConfigurationNotFound(state);
}

export function getSelectedViewName(designArea) {
    return (
        get(designArea, 'customData.selectedCameraView') || // used by the 3D camera positions
        get(designArea, 'designView.identifier') || // used by the 2D design view associations
        get(designArea, 'identifier') || // fallback to the design area identifier (currently no known use case)
        'default' // if no design area selected use the default view
    );
}

export const hasPlaceHolderImagesForActiveDesignArea = state => {
    const designData = getDesignDataForSelectedDesignArea(state);
    const canvasObjects = get(designData, 'canvasData.objects') || null;
    return (
        canvasObjects &&
        !!canvasObjects.find(object => object.type === 'Image' && object.imageData.isPlaceHolderImage)
    );
};

export function isHighlighted(state) {
    return get(state, 'designArea.showHighlight') || false;
}

export function getMaxUploadSize(state) {
    return get(state, 'designArea.uploadMaxSize') || 20000000;
}

export function get2DMaxZoom(state) {
    return get(state, 'designArea.maxZoom2d') || 2.0;
}

const zeroSize = {
    width: 0,
    height: 0,
};

/**
 * Returns the canvas size in mm-s
 * @param state
 * @param defaultSize
 * @returns {*}
 */
export function getCurrentCanvasSize(state, defaultSize = zeroSize) {
    const { designProductionMethod } = getSelectedDesignAreaProperties(state);
    if (!designProductionMethod) {
        return defaultSize;
    }
    return getCanvasSizeFromDesignProductionMethod(designProductionMethod);
}

const memoizedCanvasSize = memoize((width, height, isMetric, dpi) => ({
    width,
    height,
    isMetric,
    dpi,
}));

export function getCanvasSizeFromDesignProductionMethod(designProductionMethod, defaultSize = zeroSize) {
    const { width, height, dpi } = designProductionMethod;
    if (!width || !height) {
        return defaultSize;
    }
    return memoizedCanvasSize(width, height, true, dpi || getConf('designer.dpi', 300));
}

export function getCanvasSizeFromDesignArea(state, designArea, defaultSize = zeroSize) {
    const designProductionMethod = getSelectedDesignProductionMethodForDesignArea(state, designArea);
    return designProductionMethod
        ? getCanvasSizeFromDesignProductionMethod(designProductionMethod)
        : defaultSize;
}

export function getFontSizeMin(state, designProductionMethodIdentifier = false) {
    const designProductionMethod = designProductionMethodIdentifier
        ? getDesignProductionMethodByIdentifier(state, designProductionMethodIdentifier)
        : getSelectedDesignProductionMethod(state);
    return Number(get(designProductionMethod, 'options.minFontSize')) || 5;
}

export function getElementLockState(state, designProductionMethodIdentifier = false) {
    const designProductionMethod = designProductionMethodIdentifier
        ? getDesignProductionMethodByIdentifier(state, designProductionMethodIdentifier)
        : getSelectedDesignProductionMethod(state);
    return get(designProductionMethod, 'designElementsLocked');
}

export function hasEngravingBackgroundColor(state, designProductionMethodIdentifier = false) {
    const designProductionMethod = designProductionMethodIdentifier
        ? getDesignProductionMethodByIdentifier(state, designProductionMethodIdentifier)
        : getSelectedDesignProductionMethod(state);
    return designProductionMethodHasEngravingVisualizationEffect(designProductionMethod);
}

export function isColoringDisabled(state, designProductionMethodIdentifier = false) {
    const designProductionMethod = designProductionMethodIdentifier
        ? getDesignProductionMethodByIdentifier(state, designProductionMethodIdentifier)
        : getSelectedDesignProductionMethod(state);
    const visualizationEffect = get(designProductionMethod, 'options.visualizationEffect', 'print');
    return ['engraving', 'embossing'].indexOf(visualizationEffect) !== -1;
}

export function getVisualizationEffect(designProductionMethod) {
    return get(designProductionMethod, 'options.visualizationEffect', 'print');
}

export function designProductionMethodHasEmbroideryVisualizationEffect(designProductionMethod) {
    return 'embroidery' === getVisualizationEffect(designProductionMethod);
}

export function designProductionMethodHasEngravingVisualizationEffect(designProductionMethod) {
    return 'engraving' === getVisualizationEffect(designProductionMethod);
}

export function getEngravingBackgroundColor(state, designProductionMethod, variantIdentifier = false) {
    const _designProductionMethod = designProductionMethod || getSelectedDesignProductionMethod(state) || {};
    const { engravingBackgroundColors } = _designProductionMethod;
    return get(
        find(engravingBackgroundColors, {
            itemIdentifier: variantIdentifier || getSelectedVariantIdentifier(getConfigurator(state)),
        }),
        'colorHex',
        'rgba(0, 0, 0, 0.5)'
    );
}

export function getColorOverlayData(state, designArea, variantIdentifier = false) {
    const designProductionMethod = getSelectedDesignProductionMethodForDesignArea(state, designArea);
    if (!designProductionMethodHasEngravingVisualizationEffect(designProductionMethod)) {
        return null;
    }
    return {
        color: getEngravingBackgroundColor(state, designArea, variantIdentifier),
    };
}

export function getVisualizationEffectWithOptions(state, designArea, variantIdentifier = false) {
    const designProductionMethod = getSelectedDesignProductionMethodForDesignArea(state, designArea);
    const effect = getVisualizationEffect(designProductionMethod);
    const effectOptions = {
        ...(designProductionMethodHasEngravingVisualizationEffect(designProductionMethod) && {
            fillColor: getEngravingBackgroundColor(state, designProductionMethod, variantIdentifier),
        }),
    };
    return { effect, effectOptions };
}

export const getColorPalettes = createSelector(
    state => {
        const { designProductionMethod } = getSelectedDesignAreaProperties(state);
        return designProductionMethod;
    },
    designProductionMethod => (designProductionMethod ? designProductionMethod.colorPalettes : [])
);

export function getColors(state) {
    return getColorsFromCanvasData(getDesignDataForSelectedDesignArea(state).canvasData);
}

export function getColorsWithPalette(state) {
    return getColorsFromCanvasDataWithPalette(getDesignDataForSelectedDesignArea(state).canvasData);
}

export const isValidHex = hex => /^#([0-9A-F]{3}){1,2}$/i.test(hex);

export const hexToRgb = (hex, stringify = true) => {
    // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
    hex = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, (m, r, g, b) => {
        return r + r + g + g + b + b;
    });

    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);

    if (!result) {
        return null;
    }

    const [r, g, b] = [1, 2, 3].map(i => parseInt(result[i], 16));

    if (!stringify) {
        return { r, g, b };
    }

    return `rgb(${r}, ${g}, ${b})`;
};

export const hexToRgbNumbers = hex => {
    const rgbAsString = hexToRgb(hex);
    return (
        rgbAsString &&
        rgbAsString
            .slice(4, rgbAsString.length - 1)
            .split(',')
            .map(numString => parseInt(numString))
    );
};

export const calculateColorDistance = (firstColor, secondColor) => {
    const firstRgb = hexToRgbNumbers(firstColor);
    const secondRgb = hexToRgbNumbers(secondColor);

    if (!firstRgb || !secondRgb) {
        return null;
    }

    return firstRgb
        .map((color, index) => Math.pow(color - secondRgb[index], 2))
        .reduce((accumulator, value) => accumulator + value);
};

export const rgbToHex = (r, g, b) => {
    if (r > 255 || g > 255 || b > 255) {
        throw new Error('Invalid color component');
    }

    const value = ((r << 16) | (g << 8) | b).toString(16);

    return '#' + ('000000' + value).slice(-6);
};

export const rgbString2hex = rgb => {
    rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
    return rgb && rgb.length === 4
        ? '#' +
              ('0' + parseInt(rgb[1], 10).toString(16)).slice(-2) +
              ('0' + parseInt(rgb[2], 10).toString(16)).slice(-2) +
              ('0' + parseInt(rgb[3], 10).toString(16)).slice(-2)
        : '';
};

export const rgbObjToHex = ({ r, g, b }) => rgbToHex(r, g, b);

export function getColorsFromCanvasData(canvasData) {
    const objects = get(canvasData, 'objects', []);
    const colors = [];

    for (const object of objects) {
        if (object.type === 'Text') {
            const objectColors = get(object, 'style.colors') || [];

            for (const color of objectColors) {
                colors.push(color.value);
            }
        } else if (object.type === 'Image') {
            const objectColors = Object.values(get(object, 'imageData.operations.vectorizeColorsMap') || {});

            for (const color of objectColors) {
                colors.push(color.value.startsWith('#') ? hexToRgb(color.value) : color.value);
            }
        }
    }

    return uniq(colors);
}

export function getColorsFromCanvasDataWithPalette(canvasData) {
    const objects = get(canvasData, 'objects', []);
    const colors = [];

    for (const object of objects) {
        if (object.type === 'Text') {
            const objectColors = get(object, 'style.colors') || [];

            for (const color of objectColors) {
                colors.push(color);
            }
        } else if (object.type === 'Image') {
            const objectColors = cloneDeep(
                Object.values(get(object, 'imageData.operations.vectorizeColorsMap') || {})
            );

            for (const color of objectColors) {
                if (color.value.startsWith('#')) {
                    color.value = hexToRgb(color.value);
                }

                colors.push(color);
            }
        }
    }

    return uniqWith(
        colors,
        (color1, color2) => color1.identifier === color2.identifier && color1.value === color2.value
    );
}

export function findSmallestFontSizeInCanvasData(canvasData) {
    const objects = get(canvasData, 'objects', []);
    return Math.min.apply(
        0,
        objects.map(object => object.fontSize || Infinity)
    );
}

export const createColorData = (identifier, paletteIdentifier, custom, value) => {
    const data = {
        color: identifier,
        palette: paletteIdentifier,
    };

    if (custom) {
        data.custom = true;
    }

    return {
        identifier: JSON.stringify(data),
        value: value.toLowerCase(),
    };
};

export const parseColorData = jsonStr => {
    let colorData;

    try {
        colorData = JSON.parse(jsonStr);
    } catch (e) {
        // eslint-disable-next-line no-console
        console.error(`failed to parse color data: ${jsonStr}`);
    }

    return {
        palette: null,
        color: null,
        ...colorData,
    };
};

export const getCameraViewListForDesignAreaList = (filteredDesignAreas, designedAreas) =>
    ['default'].concat(
        filteredDesignAreas
            // get the design area objects by their id
            .filter(designArea => designedAreas.indexOf(designArea.identifier) !== -1)
            // get the camera view values
            .map(designArea => get(designArea, 'customData.selectedCameraView'))
            // remove empty values and duplicates
            .filter((viewName, index, arr) => viewName && index === arr.indexOf(viewName))
            // make them lower case
            .map(viewName => viewName.toLowerCase())
    );

export const getDesignViewListForDesignAreas = (state, designAreas) => {
    const {
        designView: { designViews },
        configurationMode: {
            availableModes: { designer: designerAvailable },
        },
    } = state;

    if (!designerAvailable) {
        return designViews;
    }

    const designViewList = [];
    for (const designView of designViews) {
        const designAreaList = [];
        for (const designArea of designView.designAreas) {
            if (!designAreas || designAreas.indexOf(designArea.identifier) !== -1) {
                designAreaList.push(recalculateSingleDesignArea(state, designArea));
            }
        }
        if (designAreaList.length) {
            designViewList.push({
                ...designView,
                designAreas: designAreaList.sort(compareDesignAreasBySize),
            });
        }
    }
    return designViewList;
};

export const getDesignAreaFromSelectedDesignView = state => {
    const {
        designArea: { filteredDesignAreas },
        designView: { selectedDesignView },
    } = state;
    return find(filteredDesignAreas, ['designView.identifier', selectedDesignView.identifier])?.identifier;
};

export const getDefaultDesignAreaIdentifierFromProductionMethod = state => {
    //return the first designArea with isDefault: true due to api call accepts multiple productionmethods to be default
    const {
        designArea: { filteredDesignAreas },
    } = state;
    const defaultDesignArea =
        filteredDesignAreas &&
        filteredDesignAreas.find(
            designArea => !!designArea.designProductionMethods.find(method => method.isDefault)
        );
    if (defaultDesignArea) {
        return defaultDesignArea.identifier;
    } else {
        return null;
    }
};

export const getDefaultColorsFromDesignProductionMethod = designProductionMethod =>
    get(designProductionMethod, 'defaultColors') || {};

export const getDefaultTextColor = (state, colorIndex = null) => {
    const colorPalettes = getColorPalettes(state);

    const defaultColor = {
        identifier: 'ff0000',
        paletteIdentifier: null,
        custom: true,
        value: '#ff0000',
    };

    if (!colorPalettes.length) {
        return defaultColor;
    }

    if (colorIndex !== null) {
        if (colorPalettes[0].colors.length <= colorIndex) {
            return defaultColor;
        }

        return {
            identifier: colorPalettes[0].colors[colorIndex].identifier,
            paletteIdentifier: colorPalettes[0].identifier,
            custom: false,
            value: '#' + colorPalettes[0].colors[colorIndex].hex_value,
        };
    }

    const designProductionMethod = getSelectedDesignProductionMethod(state);
    const defaultColors = getDefaultColorsFromDesignProductionMethod(designProductionMethod);
    const variantIdentifier = getSelectedVariantIdentifier(getConfigurator(state));

    if (defaultColors && defaultColors[variantIdentifier]) {
        const colorPalette = find(colorPalettes, {
            identifier: Object.keys(defaultColors[variantIdentifier])[0],
        });

        if (colorPalette) {
            const color = find(colorPalette.colors, {
                identifier: defaultColors[variantIdentifier][colorPalette.identifier],
            });

            if (color) {
                return {
                    identifier: color.identifier,
                    paletteIdentifier: colorPalette.identifier,
                    custom: false,
                    value: '#' + color.hex_value,
                };
            }
        }
    }

    const paletteDefaultColorIdentifier = get(colorPalettes[0], 'defaultColor.identifier', '');
    const paletteDefaultColor = find(colorPalettes[0].colors, {
        identifier: paletteDefaultColorIdentifier,
    });

    if (paletteDefaultColor) {
        return {
            identifier: paletteDefaultColor.identifier,
            paletteIdentifier: colorPalettes[0].identifier,
            custom: false,
            value: '#' + paletteDefaultColor.hex_value,
        };
    }

    if (colorPalettes[0].colors.length) {
        return {
            identifier: colorPalettes[0].colors[0].identifier,
            paletteIdentifier: colorPalettes[0].identifier,
            custom: false,
            value: '#' + colorPalettes[0].colors[0].hex_value,
        };
    }

    return defaultColor;
};

export const isPlaceholderContent = content => {
    return content.indexOf('data-placeholder="true"') !== -1;
};

export const contentHasText = content => {
    const div = document.createElement('div');

    div.innerHTML = content;

    return /\S/.test(div.textContent);
};

export const getDesignAreaImageCompatibilityInfo = designProductionMethod => {
    const colorPalettes = (get(designProductionMethod, 'colorPalettes') || [])
        .map(({ identifier }) => identifier)
        .sort();
    const vectorsRequired = !!get(designProductionMethod, 'options.vectorsRequired');
    const maxColorAmount = get(designProductionMethod, 'options.maxColorAmount', 0);
    const vectorizedLogoMandatory = get(designProductionMethod, 'options.vectorizedLogoMandatory', false);
    return { colorPalettes, vectorsRequired, maxColorAmount, vectorizedLogoMandatory };
};

export const getCurrentCompatibilityInfoHash = state =>
    getDesignAreaImageCompatibilityInfo(getSelectedDesignProductionMethod(state));

export const areHashesCompatible = (storedHash, targetHash) => {
    return Boolean(
        !targetHash ||
            (storedHash &&
                isEqual(storedHash.colorPalettes, targetHash.colorPalettes) &&
                (!targetHash.vectorsRequired || storedHash.vectorsRequired) &&
                (!targetHash.vectorizedLogoMandatory || storedHash.vectorizedLogoMandatory) &&
                (!targetHash.maxColorAmount || storedHash.maxColorAmount <= targetHash.maxColorAmount))
    );
};

export const getVectorizedImageColor = state => {
    const selectedDesignProductionMethod = getSelectedDesignProductionMethod(state);
    const selectedImage = get(state, 'imageGallery.selectedImage', {});
    let reversedUserImages = get(state, 'imageGallery.userImages', [])
        .slice()
        .reverse();
    if (
        selectedImage &&
        reversedUserImages.length > 0 &&
        reversedUserImages.find(image => image.originalFileName === selectedImage.originalFileName) &&
        selectedImage.originalFileName !== reversedUserImages[0].originalFileName
    ) {
        const currentLastImage = reversedUserImages.find(
            image => image.originalFileName === selectedImage.originalFileName
        );
        const imagesWithoutSelectedImage = reversedUserImages.filter(image => image !== currentLastImage);
        reversedUserImages = [currentLastImage, ...imagesWithoutSelectedImage];
    }
    for (const image of reversedUserImages) {
        const objectColors = values(get(image, 'operations.vectorizeColorsMap'));
        if (!objectColors || !objectColors.length) {
            continue;
        }
        if (isImageCompatible(state, image)) {
            return first(objectColors);
        } else {
            const replacedColor = first(
                getMissingColorPalettesColors(
                    first(objectColors) ? [first(objectColors)] : [],
                    selectedDesignProductionMethod ? selectedDesignProductionMethod.colorPalettes : []
                )
            );
            return get(replacedColor, 'closestColor');
        }
    }
    return {};
};

export const areAllDesignAreasEmpty = ({ configuration }) => {
    const designdata = get(configuration, 'designdata', {});
    for (const key in designdata) {
        if (!designdata.hasOwnProperty(key)) {
            continue;
        }
        if (designdata[key].canvasData) {
            return false;
        }
    }
    return true;
};

export const hasLastEditedDesignArea = designArea => {
    const lastSelectedDesignAreaIdentifier = get(designArea, 'lastSelectedDesignAreaIdentifier', {});
    const previousEditedDesignArea = get(designArea, 'previousEditedDesignArea', {});
    return !isEmpty(lastSelectedDesignAreaIdentifier) || !isEmpty(previousEditedDesignArea);
};

export const getDesignAreaPreSelection = identifier => {
    const designerPreSelection = getConf('designerPreSelection', {});

    if (!designerPreSelection.designAreas || !designerPreSelection.designAreas.length) {
        return {};
    }

    const preSelection = find(designerPreSelection.designAreas, { identifier });

    return preSelection ? preSelection : {};
};

export const getDesignAreaColorAmount = (maxColorAmount, preSelectionColorAmount) => {
    let amount = maxColorAmount > 0 ? 1 : null;

    if (preSelectionColorAmount > 0) {
        amount = preSelectionColorAmount > maxColorAmount ? maxColorAmount : preSelectionColorAmount;
    }

    return amount;
};

export const isVectorizedLogoMandatory = designProductionMethod =>
    !!designProductionMethod?.options?.vectorizedLogoMandatory;

export const getVectorizeForDesignProductionMethods = (state, designProductionMethodIdentifier) => {
    const { designProductionMethod } = getSelectedDesignAreaProperties(state);
    const newProductionMethod = getDesignProductionMethodByIdentifier(
        state,
        designProductionMethodIdentifier
    );
    const currentVectorsRequired = !!get(designProductionMethod, 'options.vectorsRequired');
    const newVectorsRequired = !!get(newProductionMethod, 'options.vectorsRequired');
    return {
        currentVectorsRequired,
        newVectorsRequired,
    };
};

export const getMandatoryVectorizationForDesignProductionMethods = (
    state,
    designProductionMethodIdentifier
) => {
    const { designProductionMethod } = getSelectedDesignAreaProperties(state);
    const newProductionMethod = getDesignProductionMethodByIdentifier(
        state,
        designProductionMethodIdentifier
    );
    const currentVectorsMandatory = isVectorizedLogoMandatory(designProductionMethod);
    const newVectorsMandatory = isVectorizedLogoMandatory(newProductionMethod);

    return {
        currentVectorsMandatory,
        newVectorsMandatory,
    };
};

export const getImagesByDesignArea = (state, designAreaIdentifier) => {
    if (!designAreaIdentifier) {
        designAreaIdentifier = getSelectedDesignArea(state).identifier;
    }
    const designData = getDesignDataByDesignAreaIdentifier(state, designAreaIdentifier);
    return get(designData, 'canvasData.objects', []).filter(({ type }) => type === 'Image');
};

export function isOneLineText(state) {
    return get(getSelectedDesignProductionMethod(state), 'oneLineText', false);
}
