import { defineComponent, computed, ref, onMounted, nextTick, resolveComponent, openBlock, createElementBlock, normalizeClass, withModifiers, createVNode, createSlots, withCtx, renderSlot, createElementVNode, createCommentVNode } from 'vue';
import { isNumber } from 'lodash-es';
import { UpOutlined, DownOutlined } from '../icon';
import { useTheme } from '../_theme/useTheme';
import getPrefixCls from '../_util/getPrefixCls';
import { useNormalModel } from '../_util/use/useModel';
import useFormAdaptor from '../_util/use/useFormAdaptor';
import InputInner from '../input/inputInner.js';

const prefixCls = getPrefixCls('input-number');
var ActionEnum = /*#__PURE__*/function (ActionEnum) {
  ActionEnum[ActionEnum["PLUS"] = 0] = "PLUS";
  ActionEnum[ActionEnum["REDUCE"] = 1] = "REDUCE";
  return ActionEnum;
}(ActionEnum || {});
const inputNumberProps = {
  modelValue: Number,
  min: {
    type: Number,
    default: Number.NEGATIVE_INFINITY
  },
  max: {
    type: Number,
    default: Number.POSITIVE_INFINITY
  },
  step: {
    type: Number,
    default: 1
  },
  showStepAction: {
    type: Boolean,
    default: true
  },
  precision: Number,
  disabled: Boolean,
  placeholder: String,
  autofocus: {
    type: Boolean,
    default: false
  }
};
var script = defineComponent({
  name: 'FInputNumber',
  components: {
    InputInner,
    UpOutlined,
    DownOutlined
  },
  props: inputNumberProps,
  emits: ['update:modelValue', 'change', 'input', 'blur', 'focus'],
  setup(props, _ref) {
    let {
      emit
    } = _ref;
    useTheme();
    const {
      validate,
      isError,
      isFormDisabled
    } = useFormAdaptor({
      valueType: 'number',
      forbidChildValidate: true
    });
    const [currentValue, updateCurrentValue] = useNormalModel(props, emit);
    const innerDisabled = computed(() => props.disabled || isFormDisabled.value);
    const classes = computed(() => [`${prefixCls}`, innerDisabled.value && 'is-disabled'].filter(Boolean));
    const inputRef = ref();
    const tempValue = ref();
    const displayValue = computed(() => {
      if (tempValue.value != null) {
        return tempValue.value;
      }
      return currentValue.value;
    });

    // 获取输入值的小数位数
    const getPrecision = val => {
      if (val == null) {
        return 0;
      }
      const valueString = val.toString();
      const dotPosition = valueString.indexOf('.');
      let valuePrecision = 0;
      if (dotPosition !== -1) {
        valuePrecision = valueString.length - dotPosition - 1;
      }
      return valuePrecision;
    };

    // 数字的实际精度 （组件绑定的精度属性要处理）
    const numPrecision = computed(() => {
      const stepPrecision = getPrecision(props.step);
      if (props.precision != null) {
        const positiveIntegerPrecision = Math.abs(Math.round(props.precision));
        if (stepPrecision > positiveIntegerPrecision) {
          console.warn('[InputNumber]precision should not be less than the decimal places of step');
        }
        return positiveIntegerPrecision;
      }
      return Math.max(getPrecision(currentValue.value), stepPrecision); // 计算时可能currentvalue 无值
    });

    // 保留指定的小数位数
    const toPrecision = (num, pre) => {
      if (pre == null) {
        pre = numPrecision.value;
      }
      return Math.round(num * 10 ** pre) / 10 ** pre;
    };
    const setCurrentValue = newVal => {
      const oldVal = currentValue.value;
      if (isNumber(newVal) && props.precision != null) {
        newVal = toPrecision(newVal, props.precision);
      }
      if (newVal != null && newVal >= props.max) {
        newVal = props.max;
      }
      if (oldVal === newVal) {
        return;
      }
      tempValue.value = null;
      updateCurrentValue(newVal);
      emit('input', newVal);
      emit('change', newVal, oldVal);
      validate('input');
      validate('change');
    };
    const handleBlur = e => {
      if (tempValue.value) {
        tempValue.value = null;
      }
      // 避免输入的值小于最小值而导致无法继续输入的情况, 失焦的时候再处理
      if (currentValue.value != null && currentValue.value <= props.min) {
        currentValue.value = props.min;
      }
      emit('blur', e);
      validate('blur');
    };
    const handleInput = value => {
      tempValue.value = value;

      // 在下一个 tick 处理 tempValue，避免无法重制 displayValue
      nextTick(() => {
        if (!value.endsWith('.') && (!Number.isNaN(Number(value)) || value === '')) {
          setCurrentValue(value === '' ? null : Number(value));
        }
      });
    };
    const onFocused = e => {
      emit('focus', e);
    };
    const _calculationNum = (val, type) => {
      if (!isNumber(val) && val != null) {
        return tempValue.value;
      }
      const precisionFactor = 10 ** numPrecision.value;
      let tmp;
      if (type === ActionEnum.PLUS) {
        tmp = precisionFactor * val + precisionFactor * props.step;
      } else {
        tmp = precisionFactor * val - precisionFactor * props.step;
      }
      return toPrecision(tmp / precisionFactor);
    };
    // 是否已减小到最小值
    const minDisabled = computed(() => _calculationNum(currentValue.value, ActionEnum.REDUCE) < props.min);
    // 是否已加到最大值
    const maxDisabled = computed(() => _calculationNum(currentValue.value, ActionEnum.PLUS) > props.max);
    const calculationNum = type => {
      if (props.disabled || maxDisabled.value && type === ActionEnum.PLUS || minDisabled.value && type === ActionEnum.REDUCE || isFormDisabled.value) {
        return;
      }
      tempValue.value = null;
      setCurrentValue(_calculationNum(currentValue.value || 0, type));
    };
    const focus = () => {
      inputRef.value.focus();
    };
    onMounted(() => {
      if (props.autofocus) {
        focus();
      }
    });
    return {
      prefixCls,
      isError,
      ActionEnum,
      innerDisabled,
      classes,
      handleInput,
      onFocused,
      handleBlur,
      calculationNum,
      displayValue,
      minDisabled,
      maxDisabled,
      inputRef
    };
  }
});

function render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_UpOutlined = resolveComponent("UpOutlined");
  const _component_DownOutlined = resolveComponent("DownOutlined");
  const _component_InputInner = resolveComponent("InputInner");
  return openBlock(), createElementBlock("div", {
    class: normalizeClass(_ctx.classes),
    onDragstart: _cache[4] || (_cache[4] = withModifiers(() => {}, ["prevent"]))
  }, [createVNode(_component_InputInner, {
    ref: "inputRef",
    modelValue: _ctx.displayValue,
    disabled: _ctx.innerDisabled,
    placeholder: _ctx.placeholder,
    class: normalizeClass([`${_ctx.prefixCls}-inner`]),
    innerIsError: _ctx.isError,
    onInput: _ctx.handleInput,
    onFocus: _ctx.onFocused,
    onBlur: _ctx.handleBlur
  }, createSlots({
    suffix: withCtx(() => [renderSlot(_ctx.$slots, "suffix"), _ctx.showStepAction ? (openBlock(), createElementBlock("div", {
      key: 0,
      class: normalizeClass([`${_ctx.prefixCls}-actions`, _ctx.$slots.suffix && `${_ctx.prefixCls}-actions-suffix`])
    }, [createElementVNode("span", {
      class: normalizeClass([`${_ctx.prefixCls}-actions-increase`, {
        'is-disabled': _ctx.maxDisabled || _ctx.innerDisabled
      }]),
      onMousedown: _cache[0] || (_cache[0] = withModifiers(() => {}, ["prevent"])),
      onClick: _cache[1] || (_cache[1] = $event => _ctx.calculationNum(_ctx.ActionEnum.PLUS))
    }, [createVNode(_component_UpOutlined)], 34 /* CLASS, NEED_HYDRATION */), createElementVNode("span", {
      class: normalizeClass([`${_ctx.prefixCls}-actions-decrease`, {
        'is-disabled': _ctx.minDisabled || _ctx.innerDisabled
      }]),
      onMousedown: _cache[2] || (_cache[2] = withModifiers(() => {}, ["prevent"])),
      onClick: _cache[3] || (_cache[3] = $event => _ctx.calculationNum(_ctx.ActionEnum.REDUCE))
    }, [createVNode(_component_DownOutlined)], 34 /* CLASS, NEED_HYDRATION */)], 2 /* CLASS */)) : createCommentVNode("v-if", true)]),
    _: 2 /* DYNAMIC */
  }, [_ctx.$slots.prefix ? {
    name: "prefix",
    fn: withCtx(() => [renderSlot(_ctx.$slots, "prefix")]),
    key: "0"
  } : undefined]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "disabled", "placeholder", "class", "innerIsError", "onInput", "onFocus", "onBlur"])], 34 /* CLASS, NEED_HYDRATION */);
}

script.render = render;
script.__file = "components/input-number/input-number.vue";

export { script as default, inputNumberProps };
