import bindAll from 'lodash.bindall';
import {connect} from 'react-redux';
import paper from '@scratch/paper';
import parseColor from 'parse-color';
import PropTypes from 'prop-types';
import React from 'react';

import {changeColorIndex} from '../reducers/color-index';
import {clearSelectedItems} from '../reducers/selected-items';
import {activateEyeDropper} from '../reducers/eye-dropper';
import {changeColorHue,
    changeColorSaturation,
    changeColorBrightness,
    changeColorHSB} from '../reducers/color-picker';

import GradientTypes from '../lib/gradient-types';

import ColorPickerComponent from '../components/color-picker/color-picker.jsx';
import {MIXED} from '../helper/style-path';
import Modes from '../lib/modes';

const colorStringToHsv = hexString => {
    const hsv = parseColor(hexString).hsv;
    // Hue comes out in [0, 360], limit to [0, 100]
    hsv[0] = hsv[0] / 3.6;
    // Black is parsed as {0, 0, 0}, but turn saturation up to 100
    // to make it easier to see slider values.
    if (hsv[1] === 0 && hsv[2] === 0) {
        hsv[1] = 100;
    }
    return hsv;
};

const hsvToHex = (h, s, v) =>
    // Scale hue back up to [0, 360] from [0, 100]
    parseColor(`hsv(${3.6 * h}, ${s}, ${v})`).hex
;

// Important! This component ignores new color props except when isEyeDropping
// This is to make the HSV <=> RGB conversion stable. The sliders manage their
// own changes until unmounted or color changes with props.isEyeDropping = true.
class ColorPicker extends React.Component {
    constructor (props) {
        super(props);
        bindAll(this, [
            'getHsv',
            'handleChangeGradientTypeHorizontal',
            'handleChangeGradientTypeRadial',
            'handleChangeGradientTypeSolid',
            'handleChangeGradientTypeVertical',
            'handleHueChange',
            'handleSaturationChange',
            'handleBrightnessChange',
            'handleTransparent',
            'handleActivateEyeDropper'
        ]);

        const color = props.colorIndex === 0 ? props.color : props.color2;
        const hsv = this.getHsv(color);
        // this.state = {
        //     hue: hsv[0],
        //     saturation: hsv[1],
        //     brightness: hsv[2]
        // };
        this.props.setColorHSB(hsv[0], hsv[1], hsv[2]);
    }
    componentWillReceiveProps (newProps) {
        const {setColorHSB} = this.props;
        const color = newProps.colorIndex === 0 ? this.props.color : this.props.color2;
        const newColor = newProps.colorIndex === 0 ? newProps.color : newProps.color2;
        const colorSetByEyedropper = this.props.isEyeDropping && color !== newColor;
        if (colorSetByEyedropper || this.props.colorIndex !== newProps.colorIndex) {
            const hsv = this.getHsv(newColor);
            // this.setState({
            //     hue: hsv[0],
            //     saturation: hsv[1],
            //     brightness: hsv[2]
            // });
            setColorHSB(hsv[0], hsv[1], hsv[2]);
        }
        if (newProps.fillColor !== this.props.fillColor) {
            const hsv = this.getHsv(newColor);
            this.handleColorChange(hsv[0], hsv[1], hsv[2]);
        } else if (newProps.fillColor2 !== this.props.fillColor2) {
            const hsv = this.getHsv(newColor);
            this.handleColorChange(hsv[0], hsv[1], hsv[2]);
        }
        if (newProps.isEyeDropping && !this.props.isEyeDropping) {
            this.handleActivateEyeDropper();
        }
        if (newProps.gradientType !== this.props.gradientType) {
            if (newProps.gradientType === GradientTypes.HORIZONTAL) {
                this.handleChangeGradientTypeHorizontal();
            } else if (newProps.gradientType === GradientTypes.RADIAL) {
                this.handleChangeGradientTypeRadial();
            } else if (newProps.gradientType === GradientTypes.SOLID) {
                this.handleChangeGradientTypeSolid();
            } else if (newProps.gradientType === GradientTypes.VERTICAL) {
                this.handleChangeGradientTypeVertical();
            }
        }
    }
    getHsv (color) {
        const isTransparent = color === null;
        const isMixed = color === MIXED;
        return isTransparent || isMixed ?
            [50, 100, 100] : colorStringToHsv(color);
    }
    handleHueChange (hue) {
        // this.setState({hue: hue}, () => {
        //     this.handleColorChange();
        // });
        this.props.changeColorHue(hue);
        this.handleColorChange(hue, this.props.saturation, this.props.brightness);
    }
    handleSaturationChange (saturation) {
        // this.setState({saturation: saturation}, () => {
        //     this.handleColorChange();
        // });
        this.props.changeColorSaturation(saturation);
        this.handleColorChange(this.props.hue, saturation, this.props.brightness);
    }
    handleBrightnessChange (brightness) {
        // this.setState({brightness: brightness}, () => {
        //     this.handleColorChange();
        // });
        this.props.changeColorBrightness(brightness);
        this.handleColorChange(this.props.hue, this.props.saturation, brightness);
    }
    handleColorChange (hue, saturation, brightness) {
        // this.props.onChangeColor(hsvToHex(
        //     this.state.hue,
        //     this.state.saturation,
        //     this.state.brightness
        // ));
        this.props.onChangeColor(hsvToHex(
            hue,
            saturation,
            brightness
        ));

    }
    handleTransparent () {
        this.props.onChangeColor(null);
    }
    handleActivateEyeDropper () {
        this.props.onActivateEyeDropper(
            paper.tool, // get the currently active tool from paper
            this.props.onChangeColor
        );
    }
    handleChangeGradientTypeHorizontal () {
        this.props.onChangeGradientType(GradientTypes.HORIZONTAL);
    }
    handleChangeGradientTypeRadial () {
        this.props.onChangeGradientType(GradientTypes.RADIAL);
    }
    handleChangeGradientTypeSolid () {
        this.props.onChangeGradientType(GradientTypes.SOLID);
    }
    handleChangeGradientTypeVertical () {
        this.props.onChangeGradientType(GradientTypes.VERTICAL);
    }
    render () {
        // console.log('hsb : ', this.props.hue, this.props.saturation, this.props.brightness);
        return (
            <ColorPickerComponent
                brightness={this.props.brightness}
                color={this.props.color}
                color2={this.props.color2}
                colorIndex={this.props.colorIndex}
                gradientType={this.props.gradientType}
                hue={this.props.hue}
                isEyeDropping={this.props.isEyeDropping}
                mode={this.props.mode}
                rtl={this.props.rtl}
                saturation={this.props.saturation}
                shouldShowGradientTools={this.props.shouldShowGradientTools}
                onActivateEyeDropper={this.handleActivateEyeDropper}
                onBrightnessChange={this.handleBrightnessChange}
                onChangeGradientTypeHorizontal={this.handleChangeGradientTypeHorizontal}
                onChangeGradientTypeRadial={this.handleChangeGradientTypeRadial}
                onChangeGradientTypeSolid={this.handleChangeGradientTypeSolid}
                onChangeGradientTypeVertical={this.handleChangeGradientTypeVertical}
                onHueChange={this.handleHueChange}
                onSaturationChange={this.handleSaturationChange}
                onSelectColor={this.props.onSelectColor}
                onSelectColor2={this.props.onSelectColor2}
                onSwap={this.props.onSwap}
                onTransparent={this.handleTransparent}
            />
        );
    }
}

ColorPicker.propTypes = {
    color: PropTypes.string,
    color2: PropTypes.string,
    colorIndex: PropTypes.number.isRequired,
    gradientType: PropTypes.oneOf(Object.keys(GradientTypes)).isRequired,
    isEyeDropping: PropTypes.bool.isRequired,
    mode: PropTypes.oneOf(Object.keys(Modes)),
    onActivateEyeDropper: PropTypes.func.isRequired,
    onChangeColor: PropTypes.func.isRequired,
    onChangeGradientType: PropTypes.func,
    onSelectColor: PropTypes.func.isRequired,
    onSelectColor2: PropTypes.func.isRequired,
    onSwap: PropTypes.func,
    rtl: PropTypes.bool.isRequired,
    shouldShowGradientTools: PropTypes.bool.isRequired,
    setColorHSB: PropTypes.func,
    changeColorHue: PropTypes.func,
    changeColorSaturation: PropTypes.func,
    changeColorBrightness: PropTypes.func,
    hue: PropTypes.number,
    saturation: PropTypes.number,
    brightness: PropTypes.number,
    fillColor: PropTypes.string,
    fillColor2: PropTypes.string
};

const mapStateToProps = state => ({
    colorIndex: state.scratchPaint.fillMode.colorIndex,
    isEyeDropping: state.scratchPaint.color.eyeDropper.active,
    mode: state.scratchPaint.mode,
    rtl: state.scratchPaint.layout.rtl,
    hue: state.scratchPaint.colorPickerHSB.hue,
    saturation: state.scratchPaint.colorPickerHSB.saturation,
    brightness: state.scratchPaint.colorPickerHSB.brightness,
    fillColor: state.scratchPaint.color.fillColor,
    fillColor2: state.scratchPaint.color.fillColor2
});

const mapDispatchToProps = dispatch => ({
    clearSelectedItems: () => {
        dispatch(clearSelectedItems());
    },
    onActivateEyeDropper: (currentTool, callback) => {
        dispatch(activateEyeDropper(currentTool, callback));
    },
    onSelectColor: () => {
        dispatch(changeColorIndex(0));
    },
    onSelectColor2: () => {
        dispatch(changeColorIndex(1));
    },
    changeColorHue: hue => {
        dispatch(changeColorHue(hue));
    },
    changeColorSaturation: saturation => {
        dispatch(changeColorSaturation(saturation));
    },
    changeColorBrightness: brightness => {
        dispatch(changeColorBrightness(brightness));
    },
    setColorHSB: (hue, saturation, brightness) => {
        dispatch(changeColorHSB(hue, saturation, brightness));
    }
});

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(ColorPicker);
