<template>
  <InputFormatted
    class="hive-input-number"
    :parser="inputNumberParser"
    :formatter="formatter"
    v-bind="$attrs"
    v-on="listeners"
    :value="curValue"
    :type="formatter ? 'text' : 'number'"
    @keydown="onKeyDown"
    @change="onChange"
  >
    <template v-slot:inputSuffix>
      <div class="hive-input-number__action">
        <a
          href="javascript:;"
          :class="['hive-input-number__action-up', {
            'hive-input-number__action--disabled': upDisabled
          }]"
          @click="onUpClick"
        >
          up
        </a>
        <a
          href="javascript:;"
          :class="['hive-input-number__action-down', {
            'hive-input-number__action--disabled': downDisabled
          }]"
          @click="onDownClick"
        >
          down
        </a>
      </div>
    </template>
  </InputFormatted>
</template>

<script>
import Input from '../input';
import valueFormat from '../input/value-format';
import NP from 'number-precision';

const name = 'hive-input-number';

function getValidNum(val = '') {
  let value = String(val);

  /* eslint-disable */
  value = value
    .replace(/^-/, '*').replace('-', '').replace('*', '-')
    .replace(/[^-\d\.]/g, '').replace(/\d*\.(?=\d*\.)/g, function (dotStr) {
    return dotStr.substr(-1);
  });
  /* eslint-enable */

  if (value !== '' && !isNaN(Number(value))) {
    value = Number(value);
  }

  return value;
}

const InputFormatted = valueFormat(Input);

export default {
  name: name,
  components: {
    InputFormatted
  },
  model: {
    event: 'change'
  },
  props: {
    /**
     * 格式化value值，配合formatter使用
     */
    parser: Function,
    /**
     * 格式化value值，配合parser使用
     */
    formatter: Function,
    /**
     * 最大值
     */
    max: Number,
    /**
     * 最小值
     */
    min: Number,
    /**
     * 步长
     */
    step: { type: Number, default: 1 },
    /**
     * 值
     * @model
     */
    value: {
      default: 0,
      validator(value) {
        if (value === '') return true;
        if (typeof value === 'number') return true;
        return false;
      } }
  },
  data() {
    return {
      curValue: this.checkRange(this.$props.value)
    };
  },
  computed: {
    inputNumberParser() {
      return [
        {
          parser: this.parser
        },
        {
          parser: getValidNum,
          options: { input: true, blur: false, enter: false }
        },
        {
          parser: this.checkRange,
          options: { input: false, blur: true, enter: true }
        }
      ];
    },
    upDisabled() {
      return this.max <= this.curValue;
    },
    downDisabled() {
      return this.min >= this.curValue && typeof this.curValue !== 'undefined';
    },
    listeners() {
      const { keydown, change, ...others } = this.$listeners;
      return { ...others };
    }
  },
  watch: {
    value(value) {
      this.curValue = value;
    }
  },
  methods: {
    checkRange(value) {
      const { max, min } = this;

      if (value === '') return value;

      if (typeof min !== 'undefined' && value < min) return min;
      if (typeof max !== 'undefined' && value > max) return max;

      return value;
    },
    onUpClick() {
      this.stepChange(1);
    },
    onDownClick() {
      this.stepChange(-1);
    },
    onKeyDown(e) {
      if (this.$attrs.disabled) return;
      if (e.keyCode === 38 || e.keyCode === 40) {
        e.keyCode === 38 ? this.onUpClick() : this.onDownClick();
        e.preventDefault();
        return;
      }
      /**
       * keydown
       * @param {Object} e 事件对象
       */
      this.$emit('keydown', e);
    },
    stepChange(neg = 1) {
      if (this.$attrs.disabled) return;

      let value = this.curValue;

      value = Number(value);
      value = isNaN(value) ? 0 : value;
      value = NP.plus(value, this.step * neg);

      value = this.checkRange(value);

      this.curValue = value;
      this.$emit('change', value);
    },
    onChange(value) {
      this.curValue = value;
      /**
       * change事件
       * @param {Number} value 数值
       */
      this.$emit('change', value);
    }
  }
};
</script>
