<template>
  <div class="bx-stepper-control">
    <div
      class="bx-stepper-minus"
      :class="disabledMinusClass"
      @click="changeNum('down')"
      />
    <input
      type="number"
      v-model="num"
      class="bx-stepper-input"
      :class="disableInputClass"
      :disabled="disableInput || disabled"
      @blur="onblurFn"
      @focus="onfocusFn"
      >
    <div
      class="bx-stepper-plus"
      :class="disabledAddClass"
      @click="changeNum('up')"
      />
  </div>
</template>
<script>
import { create } from '../utils'
import Toast from '../toast'
import Emitter from '../mixins/emitter'

function washNumFn(num, precision) {
  let value = `${num}`
  if (precision) {
    value = parseFloat(num).toFixed(precision)
  } else {
    value = `${Math.round(parseFloat(num))}`
  }
  return value
}

export default create({
  name: 'stepper',
  mixins: [Emitter],
  props: {
    disabled: {
      type: Boolean,
      default: false,
    },
    disableInput: {
      type: Boolean,
      default: false,
    },
    value: {
      type: Number,
      default: 0,
    },
    min: {
      type: Number,
      default: -Infinity,
    },
    max: {
      type: Number,
      default: Infinity,
    },
    step: {
      type: Number,
      default: 1,
    },
    precision: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      num: this.value, // 绑定值
      oldNum: this.value, // 绑定老值
    }
  },
  computed: {
    disabledAddClass: {
      get() {
        if (this.disabled) {
          return 'bx-number-disabled'
        }
        if (this.max && Number(this.num) >= this.max) {
          return 'bx-number-disabled'
        }
        return ''
      },
    },
    disabledMinusClass: {
      get() {
        if (this.disabled) {
          return 'bx-number-disabled'
        }
        if (this.min && Number(this.num) <= this.min) {
          return 'bx-number-disabled'
        }
        return ''
      },
    },
    disableInputClass: {
      get() {
        if (this.disableInput) {
          return 'bx-input-disabled'
        }
        if (this.disabled) {
          return 'bx-input-disabled'
        }
        return ''
      },
    },
  },
  model: {
    prop: 'value',
    event: 'change',
  },
  watch: {
    value: {
      handler() {
        const washedValue = washNumFn(this.value, this.precision)
        if (washedValue !== this.num) {
          if (parseFloat(this.value) > this.max) {
            this.$emit('change', this.max)
            this.num = this.max
          } else if (parseFloat(this.value) < this.min) {
            this.$emit('change', this.min)
            this.num = this.min
          } else {
            this.num = washedValue
          }
        }
        if (this.value !== this.num - 0) {
          this.$emit('change', this.num - 0)
        }
      },
      immediate: true,
    },
  },
  methods: {
    // 输入框失去焦点时
    onblurFn() {
      const number = parseFloat(this.num)
      if (this.num === '') {
        Toast('请输入数字')
        this.num = this.oldNum
        return
      }
      if (Number.isNaN(Number(this.num))) {
        Toast('请输入数字')
        this.num = this.oldNum
        return
      }
      if (number > this.max) {
        Toast(`请输不大于${this.max}的数值`)
        this.num = this.max
        return
      }
      if (number < this.min) {
        Toast(`请输不小于${this.min}的数值`)
        this.num = this.min
        return
      }
      if (
        !this.num ||
        this.step.toString().split('.').length - 1 > this.precision
      ) {
        this.num = this.oldNum
      } else {
        this.num = number.toFixed(this.precision)
      }
      this.oldNum = this.num
      if (this.num !== this.oldNum) {
        this.$emit('change', parseFloat(this.num))
        this.dispatch('bxs-form-item', 'form.item.validate')
      }
      this.$emit('blur', parseFloat(this.num))
    },
    // 输入框获取焦点时
    onfocusFn() {
      if (Number.isNaN(Number(this.num))) {
        this.num = this.oldNum
      }
      if (this.num) {
        if (this.precision > 0) {
          this.num = parseFloat(this.num).toFixed(this.precision)
        } else {
          this.num = `${this.num}`
        }
      }
      this.oldNum = this.num
      this.$emit('focus', parseFloat(this.num))
      this.dispatch('bxs-form-item', 'form.item.reset')
    },
    // 加减操作
    changeNum(type) {
      const fixNum = this.precision
      const num = parseFloat(this.num)
      let tmpNum = parseFloat(this.num)
      if (this.disabled) {
        return false
      }
      const n =
        type === 'up'
          ? num + parseFloat(this.step)
          : num - parseFloat(this.step)
      if (fixNum === 0) {
        tmpNum = parseFloat(n).toFixed(fixNum)
      } else {
        tmpNum = n
        tmpNum = washNumFn(tmpNum, this.precision)
      }
      if (tmpNum > this.max) {
        tmpNum = this.max
      }
      if (tmpNum < this.min) {
        tmpNum = this.min
      }
      this.num = tmpNum
      this.num = `${this.num}`
      this.oldNum = this.num
      this.$emit(type === 'up' ? 'plus' : 'minus', parseFloat(this.num))
      this.$emit('change', parseFloat(this.num))
      this.dispatch('bxs-form-item', 'form.item.validate')
      return true
    },
  },
})
</script>
<style>
@import './index.css';
</style>
