import { __assign, __extends, __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { Component, createRef } from 'react';
import cx from 'classnames';
import { I18nReceiver as Receiver } from '../i18n';
import Decimal from 'big.js';
import Icon from '../icon';
import Input from '../input';
import Pop from '../pop';
import { InputContext } from '../input/context';
import { DisabledContext } from '../disabled';
import * as Integers from './integer';
import * as Decimals from './decimal';
import { trimLeadingPlus } from './utils';
import { hasOwnProperty } from '../utils/hasOwn';
var is = Object.is;
function getStateFromProps(props, updateValueInState) {
    var pop = {
        visible: false,
        type: '',
        text: '',
    };
    var state = props.showTooltip ? { pop: pop } : {};
    if (props.integer === true) {
        var _a = Integers.normalizeMinMax(props), min = _a.min, max = _a.max;
        return __assign(__assign(__assign({}, state), { prevProps: props, min: min, max: max, delta: Integers.getDelta(props.step) }), (updateValueInState
            ? Integers.normalizeValue(props.value, min, max)
            : {}));
    }
    else {
        var _b = Decimals.normalizeMinMax(props), min = _b.min, max = _b.max;
        return __assign(__assign(__assign({}, state), { prevProps: props, min: min, max: max, delta: Decimals.getDelta(props.decimal, props.step) }), (updateValueInState
            ? Decimals.normalizeValue(props.value, min, max, props.decimal)
            : {}));
    }
}
var NumberInput = (function (_super) {
    __extends(NumberInput, _super);
    function NumberInput(props) {
        var _this = _super.call(this, props) || this;
        _this.focused = false;
        _this.timer = null;
        _this.inputRef = createRef();
        _this.inputContext = {
            renderInner: function (children) { return _this.renderChild(children); },
        };
        _this.onUserInput = function (e) {
            var value = e.target.value;
            if (_this.props.integer === false) {
                var onInput = _this.props.onInput;
                if (Decimals.isPotentialValue(value)) {
                    _this.setState({
                        input: value,
                        value: Decimals.EMPTY_DECIMAL,
                    });
                }
                else if (Decimals.isDecimal(value)) {
                    _this.setState({
                        input: value,
                        value: new Decimal(trimLeadingPlus(value)),
                    });
                    onInput && onInput(value);
                }
            }
            else {
                var onInput = _this.props.onInput;
                if (Integers.isPotentialValue(value)) {
                    _this.setState({
                        input: value,
                        value: null,
                    });
                    onInput && onInput(value);
                }
                else if (Integers.isInteger(value)) {
                    var num = parseInt(value, 10) || 0;
                    _this.setState({
                        input: value,
                        value: num,
                    });
                    onInput && onInput(value);
                }
            }
        };
        _this.onFocus = function (e) {
            _this.focused = true;
            var onFocus = _this.props.onFocus;
            onFocus && onFocus(e);
        };
        _this.hideTooltip = function () {
            _this.timer && clearTimeout(_this.timer);
            _this.timer = setTimeout(function () {
                _this.setState({
                    pop: { visible: false, text: '', type: '' },
                });
            }, 1500);
        };
        _this.onBlur = function (e) {
            _this.focused = false;
            if (_this.props.integer === true) {
                var _a = _this.props, onChange = _a.onChange, showTooltip_1 = _a.showTooltip;
                var _b = _this.state, value = _b.value, min = _b.min, max = _b.max;
                var normalized = Integers.normalizeValue(value, min, max, showTooltip_1);
                onChange === null || onChange === void 0 ? void 0 : onChange(normalized.value);
                _this.setState(normalized, function () {
                    if (showTooltip_1 && _this.state.pop.visible) {
                        _this.hideTooltip();
                    }
                });
                var onBlur = _this.props.onBlur;
                onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
            }
            else {
                var _c = _this.props, onChange = _c.onChange, decimal = _c.decimal, showTooltip_2 = _c.showTooltip;
                var _d = _this.state, input = _d.input, min = _d.min, max = _d.max;
                var normalized = Decimals.normalizeValue(input, min, max, decimal, showTooltip_2);
                onChange === null || onChange === void 0 ? void 0 : onChange(normalized.input);
                _this.setState(normalized, function () {
                    if (showTooltip_2 && _this.state.pop.visible) {
                        _this.hideTooltip();
                    }
                });
                var onBlur = _this.props.onBlur;
                onBlur && onBlur(e);
            }
        };
        _this.inc = function () {
            _this.step('inc');
        };
        _this.dec = function () {
            _this.step('dec');
        };
        _this.state = getStateFromProps(props, true);
        return _this;
    }
    NumberInput.prototype.step = function (type) {
        if (this.props.disabled) {
            return;
        }
        if (this.props.integer === true) {
            var _a = this.state, value = _a.value, min = _a.min, max = _a.max, delta = _a.delta;
            var _b = Integers.calculateLimit(value, min, max), canInc = _b.canInc, canDec = _b.canDec;
            if (value === null ||
                (type === 'inc' && !canInc) ||
                (type === 'dec' && !canDec)) {
                return;
            }
            var onChange = this.props.onChange;
            var nextValue = void 0;
            if (type === 'inc') {
                nextValue = value + delta;
            }
            else {
                nextValue = value - delta;
            }
            onChange === null || onChange === void 0 ? void 0 : onChange(nextValue);
            this.setState({
                value: nextValue,
                input: String(nextValue),
            });
        }
        else {
            var _c = this.props, onChange = _c.onChange, decimal = _c.decimal;
            var _d = this.state, value = _d.value, min = _d.min, max = _d.max, delta = _d.delta;
            var _e = Decimals.calculateLimit(value, min, max), canInc = _e.canInc, canDec = _e.canDec;
            if ((type === 'inc' && !canInc) || (type === 'dec' && !canDec)) {
                return;
            }
            var nextValue = void 0;
            if (type === 'inc') {
                nextValue = value.plus(delta);
            }
            else {
                nextValue = value.minus(delta);
            }
            var input = nextValue.toFixed(decimal);
            onChange === null || onChange === void 0 ? void 0 : onChange(input);
            this.setState({
                value: nextValue,
                input: input,
            });
        }
    };
    NumberInput.getDerivedStateFromProps = function (props, prevState) {
        var prevProps = prevState.prevProps;
        if (props === prevProps) {
            return null;
        }
        var updateValueInState = isControlled(props);
        if (props.integer !== prevProps.integer) {
            return getStateFromProps(props, updateValueInState);
        }
        if (props.integer === true) {
            var nextState_1 = __assign(__assign({}, prevState), { prevProps: props });
            var minMaxChanged_1 = false;
            if (!is(props.min, prevProps.min) || !is(props.max, prevProps.max)) {
                var _a = Integers.normalizeMinMax(props), min = _a.min, max = _a.max;
                nextState_1.min = min;
                nextState_1.max = max;
                minMaxChanged_1 = true;
            }
            if (updateValueInState &&
                (minMaxChanged_1 || !is(props.value, prevProps.value))) {
                var _b = Integers.normalizeValue(props.value, nextState_1.min, nextState_1.max), value = _b.value, input = _b.input;
                nextState_1.value = value;
                nextState_1.input = input;
            }
            return nextState_1;
        }
        var nextState = __assign(__assign({}, prevState), { prevProps: props });
        var minMaxChanged = false;
        if (!is(props.min, prevProps.min) || !is(props.max, prevProps.max)) {
            var _c = Decimals.normalizeMinMax(props), min = _c.min, max = _c.max;
            nextState.min = min;
            nextState.max = max;
            minMaxChanged = true;
        }
        if (updateValueInState &&
            (minMaxChanged ||
                !is(props.value, prevProps.value) ||
                !is(props.decimal, prevProps.decimal))) {
            var _d = Decimals.normalizeValue(props.value, nextState.min, nextState.max, props.decimal), value = _d.value, input = _d.input;
            nextState.value = value;
            nextState.input = input;
        }
        if (!is(props.step, prevProps.step) ||
            !is(props.decimal, prevProps.decimal)) {
            nextState.delta = Decimals.getDelta(props.decimal, props.step);
        }
        return nextState;
    };
    NumberInput.prototype.checkPropsValue = function () {
        if (this.props.integer === true) {
            if (this.props.value !== this.state.value) {
                var onChange = this.props.onChange;
                onChange && onChange(this.state.value);
            }
        }
        else {
            var _a = this.props, onChange = _a.onChange, decimal = _a.decimal, propsValue = _a.value;
            var value = this.state.value;
            var roundedStateValue = value.toFixed(decimal);
            var roundedPropsValue = typeof propsValue === 'number'
                ? propsValue.toFixed(decimal)
                : propsValue;
            if (onChange &&
                this.props.value !== '' &&
                this.state.input !== '' &&
                roundedPropsValue !== roundedStateValue) {
                onChange(roundedStateValue);
            }
        }
    };
    NumberInput.prototype.componentDidMount = function () {
        if ('value' in this.props && !this.focused) {
            this.checkPropsValue();
        }
    };
    NumberInput.prototype.componentDidUpdate = function (prevProps) {
        if (prevProps !== this.props && 'value' in this.props && !this.focused) {
            this.checkPropsValue();
        }
    };
    NumberInput.prototype.renderChild = function (children) {
        var _a = this.props, _b = _a.disabled, disabled = _b === void 0 ? this.context.value : _b, readOnly = _a.readOnly, showCounter = _a.showCounter, showStepper = _a.showStepper;
        var limits;
        if (this.props.integer === true) {
            var _c = this.state, min = _c.min, max = _c.max, value = _c.value;
            limits = Integers.calculateLimit(value, min, max);
        }
        else {
            var _d = this.state, value = _d.value, min = _d.min, max = _d.max;
            limits = Decimals.calculateLimit(value, min, max);
        }
        var canDec = limits.canDec, canInc = limits.canInc;
        var input = this.state.input;
        var addState = disabled || readOnly || !canInc || input === '';
        var reduceState = disabled || readOnly || !canDec || input === '';
        var upArrowClass = cx({
            'zent-number-input-arrow': true,
            'zent-number-input-arrowup': true,
            'zent-number-input-arrow-disable': addState,
        });
        var downArrowClass = cx({
            'zent-number-input-arrow': true,
            'zent-number-input-arrowdown': true,
            'zent-number-input-arrow-disable': reduceState,
        });
        var reduceCountClass = cx({
            'zent-number-input-count': true,
            'zent-number-input-countreduce': true,
            'zent-number-input-count-disable': reduceState,
        });
        var addCountClass = cx({
            'zent-number-input-count': true,
            'zent-number-input-countadd': true,
            'zent-number-input-count-disable': addState,
        });
        return (_jsxs(_Fragment, { children: [showCounter && (_jsx("div", __assign({ className: reduceCountClass, onClick: this.dec, "data-zv": 'v10.0.12' }, { children: "\u2013" }), void 0)), children, showCounter && (_jsx("div", __assign({ className: addCountClass, onClick: this.inc, "data-zv": 'v10.0.12' }, { children: "+" }), void 0)), showStepper && (_jsxs("div", __assign({ className: 'zent-number-input-arrows', "data-zv": 'v10.0.12' }, { children: [_jsx("div", __assign({ className: upArrowClass, onClick: this.inc, "data-zv": 'v10.0.12' }, { children: _jsx(Icon, { type: "up" }, void 0) }), void 0), _jsx("div", __assign({ className: downArrowClass, onClick: this.dec, "data-zv": 'v10.0.12' }, { children: _jsx(Icon, { type: "down" }, void 0) }), void 0)] }), void 0))] }, void 0));
    };
    NumberInput.prototype.renderInput = function () {
        var _a = this.props, integer = _a.integer, className = _a.className, disabled = _a.disabled, readOnly = _a.readOnly, type = _a.type, onChange = _a.onChange, showStepper = _a.showStepper, showCounter = _a.showCounter, min = _a.min, max = _a.max, decimal = _a.decimal, onInput = _a.onInput, showTooltip = _a.showTooltip, inputProps = __rest(_a, ["integer", "className", "disabled", "readOnly", "type", "onChange", "showStepper", "showCounter", "min", "max", "decimal", "onInput", "showTooltip"]);
        var input = this.state.input;
        if (showStepper && showCounter) {
            throw new Error('NumberInput: showStepper、 showCounter cannot exist at the same time');
        }
        return (_jsx(Input, __assign({ ref: this.inputRef, autoComplete: "off" }, inputProps, { readOnly: readOnly, disabled: disabled, className: cx('zent-number-input', className), value: input, onChange: this.onUserInput, onFocus: this.onFocus, onBlur: this.onBlur }), void 0));
    };
    NumberInput.prototype.render = function () {
        var _this = this;
        var pop = this.state.pop;
        return this.props.showTooltip ? (_jsx(Receiver, __assign({ componentName: 'NumberInput' }, { children: function (i18n) { return (_jsx(InputContext.Provider, __assign({ value: _this.inputContext }, { children: _jsx(Pop, __assign({ trigger: 'none', content: pop.visible ? i18n[pop.type] + pop.text : '', visible: pop.visible, position: "bottom-left" }, { children: _this.renderInput() }), void 0) }), void 0)); } }), void 0)) : (_jsx(InputContext.Provider, __assign({ value: this.inputContext }, { children: this.renderInput() }), void 0));
    };
    NumberInput.defaultProps = {
        integer: false,
        type: 'number',
        decimal: 0,
        size: 'normal',
    };
    NumberInput.contextType = DisabledContext;
    return NumberInput;
}(Component));
export { NumberInput };
function isControlled(props) {
    return hasOwnProperty(props, 'value') && hasOwnProperty(props, 'onChange');
}
export default NumberInput;
