import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _typeof from "@babel/runtime/helpers/typeof";
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
import _extends from "@babel/runtime/helpers/extends";
var _excluded = ["connectedLeft", "connectedRight", "inverse", "max", "min", "onBlur", "onChange", "onKeyDown", "size", "step", "stepper", "suffix", "value"];

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }

import React, { forwardRef, useEffect, useRef } from 'react';
import Icon from '../icon';
import { IconAddSmallOutline, IconChevronUpSmallOutline, IconChevronDownSmallOutline, IconMinusSmallOutline } from '@teamleader/ui-icons';
import theme from './theme.css';
import SingleLineInputBase from './SingleLineInputBase';
import { KEY } from '../../constants';
import { parseValue, toNumber } from './utils';
import Button from '../button';

var StepperControls = function StepperControls(_ref) {
  var inverse = _ref.inverse,
      stepperUpProps = _ref.stepperUpProps,
      stepperDownProps = _ref.stepperDownProps;
  var iconProps = {
    color: inverse ? 'teal' : 'neutral',
    element: 'button',
    tabIndex: '-1',
    tint: inverse ? 'lightest' : 'darkest',
    type: 'button'
  };
  return /*#__PURE__*/React.createElement("div", {
    className: theme['stepper']
  }, /*#__PURE__*/React.createElement(Icon, _extends({
    className: theme['stepper-up']
  }, stepperUpProps, iconProps), /*#__PURE__*/React.createElement(IconChevronUpSmallOutline, null)), /*#__PURE__*/React.createElement(Icon, _extends({
    className: theme['stepper-down']
  }, stepperDownProps, iconProps), /*#__PURE__*/React.createElement(IconChevronDownSmallOutline, null)));
};

var NumericInput = /*#__PURE__*/forwardRef(function (_ref2, forwardedRef) {
  var connectedLeft = _ref2.connectedLeft,
      connectedRight = _ref2.connectedRight,
      _ref2$inverse = _ref2.inverse,
      inverse = _ref2$inverse === void 0 ? false : _ref2$inverse,
      _ref2$max = _ref2.max,
      max = _ref2$max === void 0 ? Number.MAX_SAFE_INTEGER : _ref2$max,
      _ref2$min = _ref2.min,
      min = _ref2$min === void 0 ? Number.MIN_SAFE_INTEGER : _ref2$min,
      onBlur = _ref2.onBlur,
      onChange = _ref2.onChange,
      onKeyDown = _ref2.onKeyDown,
      size = _ref2.size,
      _ref2$step = _ref2.step,
      step = _ref2$step === void 0 ? 1 : _ref2$step,
      _ref2$stepper = _ref2.stepper,
      stepper = _ref2$stepper === void 0 ? 'suffix' : _ref2$stepper,
      _ref2$suffix = _ref2.suffix,
      suffix = _ref2$suffix === void 0 ? [] : _ref2$suffix,
      value = _ref2.value,
      others = _objectWithoutProperties(_ref2, _excluded);

  var inputElementRef = useRef(null);
  var timerRef = useRef(null);
  var timeoutRef = useRef(null);
  var valueRef = useRef(value);
  useEffect(function () {
    valueRef.current = value;
  }, [value]);

  var isMinReached = function isMinReached() {
    return toNumber(value || 0) <= min;
  };

  var isMaxReached = function isMaxReached() {
    return toNumber(value || 0) >= max;
  };

  var handleChange = function handleChange(event) {
    onChange && onChange(event, event.currentTarget.value);
  };

  var updateStep = function updateStep(n) {
    var _Object$getOwnPropert;

    var currentValue = toNumber(valueRef.current || 0);
    var stepN = step * n;
    var newValue = currentValue + stepN;

    if (newValue % step) {
      newValue = Math.ceil(currentValue / stepN) * stepN;
    }

    var newValueBoundToMinMax = parseValue(newValue, min, max);
    var currentInputElement = inputElementRef.current;

    if (!currentInputElement) {
      return;
    }

    var prototype = Object.getPrototypeOf(currentInputElement);
    var prototypeValueSetter = (_Object$getOwnPropert = Object.getOwnPropertyDescriptor(prototype, 'value')) === null || _Object$getOwnPropert === void 0 ? void 0 : _Object$getOwnPropert.set;

    if (!prototypeValueSetter) {
      return;
    }

    prototypeValueSetter.call(currentInputElement, newValueBoundToMinMax);
    currentInputElement.dispatchEvent(new Event('change', {
      bubbles: true
    }));
  };

  var handleIncreaseValue = function handleIncreaseValue() {
    updateStep(1);
  };

  var handleDecreaseValue = function handleDecreaseValue() {
    updateStep(-1);
  };

  var handleClearStepperTimer = function handleClearStepperTimer() {
    clearTimeout(timeoutRef.current);
    clearInterval(timerRef.current);
  };

  var handleDecreaseMouseDown = function handleDecreaseMouseDown() {
    handleDecreaseValue();
    timeoutRef.current = setTimeout(function () {
      timerRef.current = setInterval(function () {
        if (isMinReached()) {
          handleClearStepperTimer();
        } else {
          handleDecreaseValue();
        }
      }, 75);
    }, 300);
  };

  var handleIncreaseMouseDown = function handleIncreaseMouseDown() {
    handleIncreaseValue();
    timeoutRef.current = setTimeout(function () {
      timerRef.current = setInterval(function () {
        if (isMaxReached()) {
          handleClearStepperTimer();
        } else {
          handleIncreaseValue();
        }
      }, 75);
    }, 300);
  }; // Unlike mouse down events, key down events are "auto-repeated" while holding down the key
  // This means we don't need to use an interval and can directly rely on the handler
  // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#auto-repeat_handling


  var handleKeyDown = function handleKeyDown(event) {
    if (event.key === KEY.ArrowUp) {
      event.preventDefault();
      handleIncreaseValue();
    } else if (event.key === KEY.ArrowDown) {
      event.preventDefault();
      handleDecreaseValue();
    }

    onKeyDown && onKeyDown(event);
  };

  var handleBlur = function handleBlur(event) {
    onBlur && onBlur(event);
  };

  var getConnectedRight = function getConnectedRight() {
    if (stepper === 'connected') {
      return /*#__PURE__*/React.createElement(Button, {
        disabled: isMaxReached(),
        icon: /*#__PURE__*/React.createElement(IconAddSmallOutline, null),
        onBlur: handleBlur,
        onMouseDown: handleIncreaseMouseDown,
        onMouseUp: handleClearStepperTimer,
        onMouseLeave: handleClearStepperTimer,
        size: size
      });
    }

    return connectedRight;
  };

  var getConnectedLeft = function getConnectedLeft() {
    if (stepper === 'connected') {
      return /*#__PURE__*/React.createElement(Button, {
        disabled: isMinReached(),
        icon: /*#__PURE__*/React.createElement(IconMinusSmallOutline, null),
        onMouseDown: handleDecreaseMouseDown,
        onMouseUp: handleClearStepperTimer,
        onMouseLeave: handleClearStepperTimer,
        onBlur: handleBlur,
        size: size
      });
    }

    return connectedLeft;
  };

  var getSuffix = function getSuffix() {
    if (stepper === 'suffix') {
      return [].concat(_toConsumableArray(Array.isArray(suffix) ? suffix : [suffix]), [
      /*#__PURE__*/

      /* eslint-disable-next-line react/jsx-key */
      React.createElement(StepperControls, {
        inverse: inverse,
        stepperUpProps: {
          disabled: isMaxReached(),
          onBlur: handleBlur,
          onMouseDown: handleIncreaseMouseDown,
          onMouseUp: handleClearStepperTimer,
          onMouseLeave: handleClearStepperTimer
        },
        stepperDownProps: {
          disabled: isMinReached(),
          onBlur: handleBlur,
          onMouseDown: handleDecreaseMouseDown,
          onMouseUp: handleClearStepperTimer,
          onMouseLeave: handleClearStepperTimer
        }
      })]);
    }

    return suffix;
  };

  var setRef = function setRef(ref) {
    inputElementRef.current = ref;

    if (typeof forwardedRef === 'function') {
      forwardedRef(ref);
    } else if (_typeof(forwardedRef) === 'object' && forwardedRef !== null) {
      forwardedRef.current = ref;
    }
  };

  var restProps = _objectSpread({
    connectedLeft: connectedLeft,
    connectedRight: connectedRight,
    inverse: inverse,
    max: max,
    min: min,
    onBlur: onBlur,
    size: size,
    step: step,
    stepper: stepper
  }, others);

  return /*#__PURE__*/React.createElement(SingleLineInputBase, _extends({
    ref: setRef,
    type: "number",
    value: value,
    onChange: handleChange,
    onKeyDown: handleKeyDown
  }, restProps, {
    connectedLeft: getConnectedLeft(),
    connectedRight: getConnectedRight(),
    suffix: getSuffix()
  }));
});
NumericInput.displayName = 'NumericInput';
export default NumericInput;