var _Object$assign;

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

import React, { useCallback, useContext, useEffect, useMemo, useRef } from 'react';
import clsx from 'clsx';
import { isNaN } from '../utils/validate/number';
import { callInterceptor } from '../utils/interceptor';
import { addUnit, getSizeStyle, isDef, formatNumber, resetScroll, preventDefault } from '../utils';
import ConfigProviderContext from '../config-provider/ConfigProviderContext';
import { COMPONENT_TYPE_KEY } from '../utils/constant';
import useRefState from '../hooks/use-ref-state';
var LONG_PRESS_INTERVAL = 200;
var LONG_PRESS_START_TIME = 600;

function equal(value1, value2) {
  return String(value1) === String(value2);
} // add num and avoid float number


function add(num1, num2) {
  var cardinal = Math.pow(10, 10);
  return Math.round((num1 + num2) * cardinal) / cardinal;
}

var Stepper = function Stepper(props) {
  var _useContext = useContext(ConfigProviderContext),
      prefixCls = _useContext.prefixCls,
      createNamespace = _useContext.createNamespace;

  var _createNamespace = createNamespace('stepper', prefixCls),
      bem = _createNamespace[0];

  var format = useCallback(function (value) {
    var min = props.min,
        max = props.max,
        allowEmpty = props.allowEmpty,
        decimalLength = props.decimalLength,
        integer = props.integer;

    if (allowEmpty && value === '') {
      return value;
    }

    value = formatNumber(String(value), !integer);
    value = value === '' ? 0 : +value;
    value = isNaN(value) ? +min : value;
    value = Math.max(Math.min(+max, value), +min); // format decimal

    if (isDef(decimalLength)) {
      value = value.toFixed(+decimalLength);
    }

    return value;
  }, [props.min, props.max, props.allowEmpty, props.decimalLength, props.integer]);

  var getInitialValue = function getInitialValue() {
    var _props$value;

    var defaultValue = (_props$value = props.value) != null ? _props$value : props.defaultValue;
    var value = format(defaultValue);
    return value;
  };

  var actionType;
  var inputRef = useRef(null);
  var innerEffectRef = useRef(false);

  var _useRefState = useRefState(function () {
    return getInitialValue();
  }),
      current = _useRefState[0],
      setCurrent = _useRefState[1],
      currentRef = _useRefState[2];

  var minusDisabled = useMemo(function () {
    return props.disabled || props.disableMinus || current <= +props.min;
  }, [props.disabled, props.disableMinus, props.min, current]);
  var plusDisabled = useMemo(function () {
    return props.disabled || props.disablePlus || current >= +props.max;
  }, [props.disabled, props.disablePlus, props.max, current]);
  var inputStyle = useMemo(function () {
    return {
      width: addUnit(props.inputWidth),
      height: addUnit(props.buttonSize)
    };
  }, [props.inputWidth, props.buttonSize]);
  var buttonStyle = useMemo(function () {
    return getSizeStyle(props.buttonSize);
  }, [props.buttonSize]);
  var innerChange = useCallback(function (value) {
    innerEffectRef.current = true;
    setCurrent(value);
    props.onChange == null ? void 0 : props.onChange(value);
  }, [props, setCurrent]);
  var check = useCallback(function () {
    var value = format(currentRef.current);

    if (!equal(value, currentRef.current)) {
      innerChange(value);
    }
  }, [format, currentRef.current]);

  var setValue = function setValue(value) {
    if (props.beforeChange) {
      callInterceptor({
        args: [value],
        interceptor: props.beforeChange,
        done: function done() {
          innerChange(value);
        }
      });
    } else {
      innerChange(value);
    }
  };

  var onChange = function onChange(e) {
    var isMinus = actionType === 'minus';

    if (actionType === 'plus' && plusDisabled || isMinus && minusDisabled) {
      props.onOverlimit == null ? void 0 : props.onOverlimit(actionType);
      return;
    }

    var diff = isMinus ? -props.step : +props.step;
    var value = format(add(+currentRef.current, diff));
    setValue(value);

    if (isMinus) {
      props.onMinus == null ? void 0 : props.onMinus(e, value);
    } else {
      props.onPlus == null ? void 0 : props.onPlus(e, value);
    }
  };

  var onInput = function onInput(event) {
    var input = event.target;
    var value = input.value;
    var decimalLength = props.decimalLength;
    var formatted = formatNumber(String(value), !props.integer); // limit max decimal length

    if (isDef(decimalLength) && formatted.includes('.')) {
      var pair = formatted.split('.');
      formatted = pair[0] + "." + pair[1].slice(0, +decimalLength);
    } // prefer number type


    var isNumeric = formatted === String(+formatted);
    setValue(isNumeric ? +formatted : formatted);
  };

  var onFocus = useCallback(function (event) {
    // readonly not work in lagacy mobile safari
    if (props.disableInput && inputRef.current) {
      inputRef.current.blur();
    } else {
      props.onFocus == null ? void 0 : props.onFocus(event);
    }
  }, [props]);

  var onBlur = function onBlur(event) {
    var input = event.target;
    var value = format(input.value);

    if (!equal(value, currentRef.current)) {
      innerChange(value);
    }

    props.onBlur == null ? void 0 : props.onBlur(event);
    resetScroll();
  };

  var isLongPress = useRef(false);
  var longPressTimer = useRef(null);

  var longPressStep = function longPressStep() {
    longPressTimer.current = setTimeout(function () {
      onChange();
      longPressStep();
    }, LONG_PRESS_INTERVAL);
  };

  var _onTouchStart = function onTouchStart() {
    if (props.longPress) {
      isLongPress.current = false;
      clearTimeout(longPressTimer.current);
      longPressTimer.current = setTimeout(function () {
        isLongPress.current = true;
        onChange();
        longPressStep();
      }, LONG_PRESS_START_TIME);
    }
  };

  var onTouchEnd = function onTouchEnd(event) {
    if (props.longPress) {
      clearTimeout(longPressTimer.current);

      if (isLongPress.current) {
        preventDefault(event);
      }
    }
  };

  var onMousedown = function onMousedown(event) {
    // fix mobile safari page scroll down issue
    // see: https://github.com/youzan/vant/issues/7690
    if (props.disableInput) {
      event.preventDefault();
    }
  };

  var createListeners = function createListeners(type) {
    return {
      onClick: function onClick(event) {
        // disable double tap scrolling on mobile safari
        event.preventDefault();
        actionType = type;
        onChange(event);
      },
      onTouchStart: function onTouchStart() {
        actionType = type;

        _onTouchStart();
      },
      onTouchEnd: onTouchEnd,
      onTouchCancel: onTouchEnd
    };
  };

  useEffect(function () {
    if (innerEffectRef.current) {
      innerEffectRef.current = false;
      return;
    }

    setCurrent(props.value);
  }, [props.value, setCurrent]);
  useEffect(function () {
    return check;
  }, [props.max, props.min, props.integer, props.decimalLength]);
  return /*#__PURE__*/React.createElement("div", {
    className: clsx(props.className, bem([props.theme])),
    style: props.style
  }, props.showMinus && /*#__PURE__*/React.createElement("button", _extends({
    type: "button",
    "aria-label": "minus",
    style: buttonStyle,
    className: clsx(bem('minus', {
      disabled: minusDisabled
    }))
  }, createListeners('minus'))), props.showInput && /*#__PURE__*/React.createElement("input", {
    ref: inputRef,
    type: props.integer ? 'tel' : 'text',
    role: "spinbutton",
    className: clsx(bem('input')),
    value: current != null ? current : '',
    style: inputStyle,
    disabled: props.disabled,
    readOnly: props.disableInput,
    inputMode: props.integer ? 'numeric' : 'decimal',
    placeholder: props.placeholder,
    "aria-valuemax": +props.max,
    "aria-valuemin": +props.min,
    "aria-valuenow": +current,
    onChange: onInput,
    onBlur: onBlur,
    onFocus: onFocus,
    onMouseDown: onMousedown,
    onClick: props.onClick
  }), props.showPlus && /*#__PURE__*/React.createElement("button", _extends({
    type: "button",
    "aria-label": "add",
    style: buttonStyle,
    className: clsx(bem('plus', {
      disabled: plusDisabled
    }))
  }, createListeners('plus'))));
};

Stepper.defaultProps = {
  theme: 'default',
  max: Number.MAX_VALUE,
  min: 1,
  step: 1,
  defaultValue: 1,
  showPlus: true,
  showMinus: true,
  showInput: true,
  longPress: true
};
export var STEPPER_KEY = Symbol('stepper');
var StepperNamespace = Object.assign(Stepper, (_Object$assign = {}, _Object$assign[COMPONENT_TYPE_KEY] = STEPPER_KEY, _Object$assign));
export default StepperNamespace;