/**
 * @file stepper.tsx
 * @author lihuanji
 *
 * 步进器
 */

import React, { PureComponent } from 'react';
import classnames from 'classnames';
const styles = require('./style.module.styl');

const addIcon = require('./add.svg');
const cutIcon = require('./cut.svg');

interface StepperProps {
    // 默认显示数量
    value?: number;
    // 步进数
    step?: number;
    // 最小数
    min?: number;
    // 最大数
    max?: number | null;
    // 获取焦点时
    onFocus?: Function;
    // 数值改变时
    onChange?: Function;
    // 离开焦点时
    onBlur?: Function;
    // 增/减 按钮点击时
    onButtonClick?: Function;
    // 是否禁用
    disabled?: boolean;
}

interface StepperState {
    num: number;
    disableAddButton: boolean;
    disableCutButton: boolean;
}

class Stepper extends PureComponent<StepperProps, StepperState> {
    static defaultProps = {
        value: null,
        step: 1,
        min: 1,
        max: null,
        onFocus: () => {},
        onChange: () => {},
        onBlur: () => {},
        onButtonClick: () => {},
        disabled: false
    };

    stepperRef: any;

    // 存储高度，用于判读是否需要滑动视图
    scroll = document.documentElement.clientHeight;

    constructor(props: StepperProps) {
        super(props);

        const value = props.value || props.min || 1;

        this.state = {
            num: value,
            disableAddButton: Boolean(props.max && value === props.max),
            disableCutButton: value === props.min
        };

        this.add = this.add.bind(this);
        this.cut = this.cut.bind(this);
        this.handleChange = this.handleChange.bind(this);
        this.handleFocus = this.handleFocus.bind(this);
        this.handleBlur = this.handleBlur.bind(this);
    }

    componentWillReceiveProps(nextProps: StepperProps) {
        if (this.props !== nextProps && nextProps.value) {
            this.setState({
                num: nextProps.value,
                disableAddButton: nextProps.value === nextProps.max,
                disableCutButton: nextProps.value === nextProps.min
            });
        }
    }

    /**
     * 增加数量
     */
    add(e: React.MouseEvent<any>) {
        e.stopPropagation();
        const { step = 1, max, value, onButtonClick } = this.props;
        const { num } = this.state;
        if (max && max <= num) {
            this.setState({
                disableAddButton: true
            });
            return;
        }

        const showValue = num + step;

        if (!value) {
            this.setState({
                num: showValue,
                disableAddButton: showValue === max,
                disableCutButton: false
            });
        }

        onButtonClick && onButtonClick(showValue);
    }

    /**
     * 删除数量
     */
    cut(e: React.MouseEvent<any>) {
        e.stopPropagation();
        const { min = 1, step = 1, value, onButtonClick } = this.props;
        const { num } = this.state;
        if (min >= num) {
            this.setState({
                disableCutButton: true
            });
            return;
        }

        const showValue = num - step;

        if (!value) {
            this.setState({
                num: showValue,
                disableAddButton: false,
                disableCutButton: showValue === min
            });
        }

        onButtonClick && onButtonClick(showValue);
    }

    /**
     * input变化
     *
     * @param {object} e 事件对象
     */
    handleChange(e: React.SyntheticEvent<any>) {
        const { onChange } = this.props;
        const val = parseInt(e.currentTarget.value, 10);

        this.setState({
            num: val
        });

        onChange && onChange(val);
    }

    handleFocus(e: React.SyntheticEvent<any>) {
        e.stopPropagation();
        e.preventDefault();

        const u = navigator.userAgent;
        const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
        // 解决安卓输入页面未上滑
        if (isAndroid) {
            const interval = setInterval(() => {
                if (document.documentElement.clientHeight !== this.scroll) {
                    this.stepperRef.scrollIntoViewIfNeeded();
                    clearInterval(interval);
                }
            }, 100);
        }

        this.props.onFocus && this.props.onFocus();
    }

    /**
     * input失去焦点
     *
     * @param {object} e 事件对象
     */
    handleBlur(e: React.SyntheticEvent<any>) {
        const { onBlur, max, min = 1 } = this.props;
        const val = parseInt(e.currentTarget.value, 10);

        let showValue = val;

        if (max && val >= max) {
            showValue = max;
        }

        if (val < min || !showValue) {
            showValue = min;
        }

        if (!this.props.value) {
            this.setState({
                num: showValue,
                disableAddButton: showValue === this.props.max,
                disableCutButton: showValue === this.props.min
            });
        }

        onBlur && onBlur(showValue);
    }

    render() {
        const { num, disableAddButton, disableCutButton } = this.state;
        const { disabled } = this.props;

        return (
            <div
                className={styles.Stepper}
                ref={ref => {
                    this.stepperRef = ref;
                }}
            >
                <div
                    className={classnames(
                        styles.StepperButton,
                        styles.StepperCut,
                        { [styles.disable]: disableCutButton || disabled }
                    )}
                    onClick={!disabled ? this.cut : undefined}
                >
                    <img className={styles.StepperIcon} src={cutIcon} />
                </div>
                <div className={styles.StepperPut}>
                    <input
                        disabled={disabled}
                        onChange={this.handleChange}
                        onBlur={this.handleBlur}
                        onFocus={this.handleFocus}
                        onClick={this.handleFocus}
                        value={num}
                        type="number"
                    />
                </div>
                <div
                    className={classnames(
                        styles.StepperButton,
                        styles.StepperAdd,
                        { [styles.disable]: disableAddButton || disabled }
                    )}
                    onClick={!disabled ? this.add : undefined}
                >
                    <img className={styles.StepperIcon} src={addIcon} />
                </div>
            </div>
        );
    }
}

export default Stepper;
