import React from 'react';
import PropTypes from 'prop-types';
import find from 'lodash/find';
import values from 'lodash/values';
import get from 'lodash/get';
import uniqBy from 'lodash/uniqBy';
import size from 'lodash/size';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import TextField from '@material-ui/core/TextField';
import Grid from '@material-ui/core/Grid';
import EditIcon from '@material-ui/icons/Edit';
import DeleteIcon from '@material-ui/icons/Delete';
import RemoveIcon from '@material-ui/icons/Close';
import Dialog from '@material-ui/core/Dialog';
import Button from '@material-ui/core/Button';
import FormatPaint from '@material-ui/icons/FormatPaint';
import MenuItem from '@material-ui/core/MenuItem';
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
import { t, T } from 'Framework/i18n';
import { createColorData, isValidHex, parseColorData } from 'App/Reducers/DesignArea/Selectors';
import AnalyticsWrapper from 'App/Shared/Components/Analytics/AnalyticsWrapper';
import MessageBox from 'App/Shared/Components/MessageBox';
import getContrastText from 'App/Utils/getContrastText';
import ColorPalettes from '../ColorPalettes';
import Select from '../Select';
import clsx from 'clsx';

const styles = theme => ({
    infoText: {
        fontStyle: 'italic',
        fontSize: 12,
        color: '#666',
    },
    maxColorError: {
        color: '#f00',
    },
    colorsContainer: {
        paddingLeft: 16,
        maxHeight: 144,
        overflowY: 'auto',
        marginTop: 15,
        [theme.breakpoints.down('xs')]: {
            width: 'calc(100% - 18px)',
            paddingLeft: 0,
            marginBottom: 0,
            margin: 'auto',
        },
    },
    slider: {
        padding: '24px 0px',
    },
    gridGrow: {
        maxWidth: 150,
        flex: '1 1 100%',
    },
    colorBox: {
        width: 32,
        height: 32,
        background: 'red',
        borderRadius: '50%',
        borderColor: '#212121',
        boxShadow: '0px 0px 2px',
    },
    editButton: {
        cursor: 'pointer',
        color: theme.palette.primary.darkText,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'space-around',
    },
    deleteContainer: {
        minWidth: 32,
    },
    deleteButton: {
        cursor: 'pointer',
    },
    editButtonDisabled: {
        cursor: 'default',
    },
    colorInput: {
        textAlign: 'center',
        color: theme.palette.primary.darkText,
        textTransform: 'capitalize',
        fontWeight: 'bold',
        textOverflow: 'ellipsis',
        overflow: 'hidden',
        fontSize: 15,
        cursor: 'pointer',
    },
    justifyGrid: {
        [theme.breakpoints.down('xs')]: {
            justifyContent: 'space-between',
        },
    },
    buttonContainer: {
        margin: '12px -12px',
        display: 'flex',
        justifyContent: 'space-between',
        '& > *': {
            margin: '0 12px',
            flexGrow: 1,
            flexBasis: 0,
            fontSize: '14px',
            textTransform: 'none',
            fontWeight: 'bold',
            minHeight: '60px',
            maxWidth: '50%',
            '& > div': {
                minHeight: '60px',
            },
            [theme.breakpoints.down('xs')]: {
                margin: 0,
            },
        },
        [theme.breakpoints.down('xs')]: {
            display: 'flex',
            margin: '24px 0px',
            '& > *:first-child': {
                maxWidth: '190px',
            },
            '& button': {
                marginLeft: 12,
            },
        },
    },
    resetButtonText: {
        textTransform: 'none',
        fontWeight: 'bold',
    },
    vectorsNotRequired: {
        marginTop: 10,
        textTransform: 'none',
    },
    listItemText: {
        fontSize: '12px',
        lineHeight: '40px',
        [theme.breakpoints.down('xs')]: {
            lineHeight: '56px',
        },
    },
});

class ImageColorize extends React.Component {
    static propTypes = {
        classes: PropTypes.object,
        width: PropTypes.string,
        vectorize: PropTypes.bool,
        onVectorizeToggleChange: PropTypes.func,
        vectorizeToggleDisabled: PropTypes.bool,
        vectorizeThreshold: PropTypes.number,
        onVectorizeThresholdChange: PropTypes.func,
        onColorSelectClick: PropTypes.func,
        onColorRemoveClick: PropTypes.func,
        colorPalettes: PropTypes.array,
        vectorizeColorsMap: PropTypes.object,
        disableInputs: PropTypes.bool,
        maxColorAmount: PropTypes.number,
        colorAmount: PropTypes.number,
        usedColors: PropTypes.array,
        inputRef: PropTypes.object,
        onColorImageStateReset: PropTypes.func,
        aggregatedColors: PropTypes.object,
        isLoading: PropTypes.bool,
        imageColorsWereEdited: PropTypes.bool,
        vectorsRequired: PropTypes.bool,
        colorAmountList: PropTypes.array,
        designProductionMethodName: PropTypes.string,
        customControlElements: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
    };

    state = {
        selectedColor: null,
        selectedColorPalette: null,
        vectorizeThreshold: 0,
        isThresholdSliderDisabled: false,
        designProductionMethodName: '',
        vectorizeRequested: false,
    };

    componentDidMount() {
        const { vectorizeThreshold } = this.props;
        this.setState({ vectorizeThreshold });
    }

    componentDidUpdate(prevProps) {
        const { vectorizeThreshold, vectorizeColorsMap } = this.props;
        if (
            vectorizeThreshold !== prevProps.vectorizeThreshold ||
            size(vectorizeColorsMap) !== size(prevProps.vectorizeColorsMap)
        ) {
            this.setState({ vectorizeThreshold });
        }
    }

    onVectorizeThresholdChange = event => {
        const { onVectorizeThresholdChange } = this.props;
        const thresholdValue = event.target.value;
        this.setState({
            prevThreshold: thresholdValue,
            vectorizeThreshold: thresholdValue,
        });
        onVectorizeThresholdChange && onVectorizeThresholdChange(thresholdValue);
    };

    onColorSelectClick = (value, identifier, paletteIdentifier, custom) => {
        const { onColorSelectClick } = this.props;
        const colorKey = this.state.selectedColor;
        this.setState({ selectedColor: null });

        const createdColor = createColorData(identifier, paletteIdentifier, custom, '#' + value);

        onColorSelectClick && onColorSelectClick(colorKey, createdColor);
    };

    onColorPaletteClose = () => {
        this.setState({ selectedColor: null });
    };

    onEditClick = colorKey => {
        this.setState({ selectedColor: colorKey });
    };

    resetImageState = async () => {
        const { onColorImageStateReset } = this.props;
        onColorImageStateReset && (await onColorImageStateReset());
    };

    getColorName = color => {
        const { colorPalettes } = this.props;
        const data = parseColorData(color.identifier);

        if (!isValidHex(color.value)) {
            return data.color + ` (${t('imageEditDialog.customColor')})`;
        }

        const colorPalette = find(colorPalettes, { identifier: data.palette });

        if (!colorPalette) {
            return data.color.toUpperCase();
        }

        const paletteColor = find(colorPalette.colors, { identifier: data.color });

        if (!paletteColor) {
            return data.color.toUpperCase();
        }

        return paletteColor.title;
    };

    getColorValue = color => {
        const { value } = color;

        return isValidHex(value) ? value : '#000000';
    };

    onVectorizeToggleChange = (e, value) => {
        const { onVectorizeToggleChange } = this.props;
        this.setState({
            vectorizeRequested: value,
        });
        onVectorizeToggleChange && onVectorizeToggleChange(value);
    };

    validateAmount = () => {
        const { maxColorAmount, colorAmount } = this.props;

        return !maxColorAmount || colorAmount <= maxColorAmount;
    };

    getSelectedColorPalette = color => {
        const { colorPalettes } = this.props;
        const { selectedColorPalette } = this.state;
        const colorData = parseColorData(color.identifier);
        const colorPalette = find(colorPalettes, { identifier: selectedColorPalette || colorData.palette });
        return colorPalette || colorPalettes[0];
    };

    getColorAmountMessage = () => {
        const { colorAmount, maxColorAmount } = this.props;

        if (!maxColorAmount) {
            return t('colorAmountIndicator.unlimitedColors');
        }

        if (colorAmount > maxColorAmount) {
            return t('colorAmountIndicator.warning', { colorAmount, maxColorAmount });
        }

        return t('colorAmountIndicator.ok', { colorAmount });
    };

    getColors = (vectorizeColorsMap, colorPalettes) => {
        const { usedColors } = this.props;
        try {
            const imageColors = values(vectorizeColorsMap);
            const usedImageColors = [];
            imageColors.forEach(color => {
                const identifier = get(color, 'identifier');
                const parsedColor = JSON.parse(identifier);
                if (!parsedColor.custom) {
                    const colorPalette = find(colorPalettes, { identifier: parsedColor.palette }) || {};
                    const colors = find(colorPalette.colors, { identifier: parsedColor.color });
                    usedImageColors.push({ ...colors, value: color.value, palette: colorPalette.identifier });
                }
            });
            return uniqBy([].concat(usedImageColors, usedColors), 'identifier');
        } catch {
            // eslint-disable-next-line no-console
            console.error('failed to parse color data');
            return null;
        }
    };

    onColorPaletteChange = identifier => {
        this.setState({
            selectedColorPalette: identifier,
        });
    };

    renderColorizeTools() {
        const {
            classes,
            colorPalettes,
            vectorizeColorsMap,
            disableInputs,
            width,
            vectorize,
            inputRef,
            aggregatedColors,
            isLoading,
            imageColorsWereEdited,
            colorAmountList,
            customControlElements,
        } = this.props;
        const { selectedColor, vectorizeThreshold, vectorizeRequested } = this.state;

        const { onColorRemoveClick } = this.props;

        const thresholdValue = colorAmountList.indexOf(vectorizeThreshold) === -1 ? 0 : vectorizeThreshold;
        const amountIsValid = this.validateAmount();
        const aggregatedColorKeys = Object.keys(aggregatedColors);

        return (
            <React.Fragment>
                {customControlElements}
                <MessageBox
                    ref={inputRef}
                    type={amountIsValid ? 'success' : 'error'}
                    text={this.getColorAmountMessage()}
                />

                <div className={classes.buttonContainer}>
                    <AnalyticsWrapper targetId="image_edit_colorize_found_colors">
                        <Select
                            bold
                            value={thresholdValue}
                            onChange={this.onVectorizeThresholdChange}
                            readOnly={false}
                            iconClass={''}
                            disabled={disableInputs}
                            error={!isLoading && !thresholdValue}
                        >
                            <MenuItem disabled value={0}>
                                {' '}
                                <Typography className={classes.listItemText} noWrap>
                                    {t('imageEditDialog.changeColorAmount')}
                                </Typography>
                            </MenuItem>
                            {colorAmountList.map(colorAmount => (
                                <MenuItem key={colorAmount} value={colorAmount}>
                                    {' '}
                                    <Typography className={classes.listItemText} noWrap>
                                        {colorAmount === 1
                                            ? t('imageEditDialog.imageColor', { amount: colorAmount })
                                            : t('imageEditDialog.imageColors', { amount: colorAmount })}
                                    </Typography>
                                </MenuItem>
                            ))}
                        </Select>
                    </AnalyticsWrapper>
                    {(imageColorsWereEdited || vectorizeRequested) && (
                        <Button
                            variant="outlined"
                            onClick={this.resetImageState}
                            disabled={isLoading}
                            startIcon={<DeleteIcon />}
                        >
                            <Typography className={classes.resetButtonText}>
                                {t('imageEditDialog.resetButton')}
                            </Typography>
                        </Button>
                    )}
                </div>
                {vectorize && (
                    <Grid container spacing={2} className={classes.colorsContainer}>
                        {aggregatedColorKeys.map(colorKey => {
                            const background = this.getColorValue(vectorizeColorsMap[colorKey]);
                            return (
                                <Grid item key={colorKey} sm={6} xs={12}>
                                    <Grid
                                        container
                                        spacing={1}
                                        alignItems="flex-end"
                                        wrap="nowrap"
                                        className={classes.justifyGrid}
                                    >
                                        <Grid item>
                                            <AnalyticsWrapper targetId="image_colorize" data={colorKey}>
                                                <div
                                                    className={clsx(
                                                        classes.colorBox,
                                                        classes.editButton,
                                                        disableInputs && classes.editButtonDisabled
                                                    )}
                                                    style={{
                                                        background,
                                                    }}
                                                    onClick={() =>
                                                        !disableInputs && this.onEditClick(colorKey)
                                                    }
                                                >
                                                    <EditIcon
                                                        style={{ color: getContrastText(background) }}
                                                    />
                                                </div>
                                            </AnalyticsWrapper>
                                        </Grid>
                                        <Grid item className={classes.gridGrow}>
                                            <TextField
                                                disabled
                                                fullWidth
                                                onClick={() => !disableInputs && this.onEditClick(colorKey)}
                                                value={this.getColorName(vectorizeColorsMap[colorKey])}
                                                translate="no"
                                                InputProps={{ disableUnderline: true }}
                                                inputProps={{ className: classes.colorInput }}
                                            />
                                        </Grid>
                                        <Grid item className={classes.deleteContainer}>
                                            {aggregatedColorKeys.length > 1 && (
                                                <RemoveIcon
                                                    disabled
                                                    className={clsx(
                                                        classes.deleteButton,
                                                        disableInputs && classes.editButtonDisabled
                                                    )}
                                                    onClick={() =>
                                                        !disableInputs && onColorRemoveClick(colorKey)
                                                    }
                                                />
                                            )}
                                        </Grid>
                                    </Grid>
                                </Grid>
                            );
                        }, this)}
                    </Grid>
                )}

                {colorPalettes && colorPalettes.length > 0 && selectedColor && (
                    <Dialog
                        open={selectedColor !== null}
                        maxWidth="xs"
                        fullWidth={true}
                        fullScreen={isWidthDown('xs', width)}
                        onClose={this.onColorPaletteClose}
                    >
                        <ColorPalettes
                            selectedColor={vectorizeColorsMap[selectedColor]}
                            colorSelectClick={this.onColorSelectClick}
                            colorPalettes={colorPalettes}
                            usedColors={this.getColors(vectorizeColorsMap, colorPalettes)}
                            palette={this.getSelectedColorPalette(vectorizeColorsMap[selectedColor])}
                            closeColorPalettes={this.onColorPaletteClose}
                            colorPaletteChange={this.onColorPaletteChange}
                        />
                    </Dialog>
                )}
            </React.Fragment>
        );
    }

    render() {
        const { classes, vectorize, designProductionMethodName } = this.props;

        return vectorize ? (
            this.renderColorizeTools()
        ) : (
            <React.Fragment>
                <Typography variant="body1" component="div">
                    {T('imageEditDialog.imageWithoutVectorization', { designProductionMethodName })}
                </Typography>
                <Button
                    variant="outlined"
                    startIcon={<FormatPaint />}
                    className={classes.vectorsNotRequired}
                    onClick={e => this.onVectorizeToggleChange(e, true)}
                >
                    {t('imageEditDialog.editColors')}
                </Button>
            </React.Fragment>
        );
    }
}

export default withStyles(styles, { name: 'ImageColorize' })(
    withWidth({ initialWidth: 'lg' })(ImageColorize)
);
