<template>
  <div
    class="el_home"
    :class="{
      'showCompanys-filtercurrency': showCompanys === 'filtercurrency',
    }"
  >
    <span v-if="unit" class="unit">
      {{ unit }}
    </span>
    <div
      :class="[
        'el-input-number',
        inputNumberSize ? 'el-input-number--' + inputNumberSize : '',
        { 'is-disabled': inputNumberDisabled },
        { 'is-without-controls': !controls },
        { 'is-controls-right': controlsAtRight },
      ]"
      @dragstart.prevent
    >
      <span
        v-if="controls"
        v-repeat-click="decrease"
        class="el-input-number__decrease"
        role="button"
        :class="{ 'is-disabled': minDisabled }"
        @keydown.enter="decrease"
      >
        <i :class="`el-icon-${controlsAtRight ? 'arrow-down' : 'minus'}`"></i>
      </span>
      <span
        v-if="controls"
        v-repeat-click="increase"
        class="el-input-number__increase"
        role="button"
        :class="{ 'is-disabled': maxDisabled }"
        @keydown.enter="increase"
      >
        <i :class="`el-icon-${controlsAtRight ? 'arrow-up' : 'plus'}`"></i>
      </span>

      <el-input
        ref="input"
        :value="displayValue"
        :placeholder="placeholder"
        :disabled="inputNumberDisabled"
        :size="inputNumberSize"
        :max="max"
        :min="min"
        :name="name"
        :label="label"
        @blur="handleBlur"
        @focus="handleFocus"
        @input="handleInput"
        @change="handleInputChange"
      ></el-input>
      <slot name="exhibitText"></slot>
      <!-- @keydown.up.native.prevent="increase"
      @keydown.down.native.prevent="decrease" -->
    </div>
    <span v-if="company" style="margin-left: 8px; white-space: nowrap">
      {{ company }}
    </span>
  </div>
</template>
<script>
  import ElInput from 'element-ui/packages/input'
  import Focus from 'element-ui/src/mixins/focus'
  import RepeatClick from 'element-ui/src/directives/repeat-click'
  export default {
    name: 'ElInputNumber',
    mixins: [Focus('input')],
    inject: {
      elForm: {
        default: '',
      },
      elFormItem: {
        default: '',
      },
    },
    directives: {
      repeatClick: RepeatClick,
    },
    components: {
      ElInput,
    },
    props: {
      unit: {
        type: String,
        default: '',
      },
      step: {
        type: Number,
        default: 1,
      },
      stepStrictly: {
        type: Boolean,
        default: false,
      },
      max: {
        type: Number,
      },
      min: {
        type: Number,
      },
      value: {
        type: [Number, String],
        default: 0,
      },
      disabled: Boolean,
      size: String,
      controls: {
        type: [Boolean, String],
        default: true,
      },
      controlsPosition: {
        type: String,
        default: '',
      },
      name: String,
      label: String,
      placeholder: String,
      precision: {
        type: Number,
        validator(val) {
          return val >= 0 && val === parseInt(val, 10)
        },
      },
      company: String,
      thousandsNumber: {
        type: String,
        default: '',
      },
      showCompanys: {
        type: String,
        default: '',
      },
    },
    data() {
      return {
        currentValue: null,
        userInput: null,
        numberMax: 999999999,
        numberMin: -999999999,
      }
    },
    computed: {
      minDisabled() {
        return (
          this._decrease(this.value, this.step) < this.min ||
          this.value > this.numberMax ||
          this.value < this.numberMin
        )
      },
      maxDisabled() {
        return (
          this._increase(this.value, this.step) > this.max ||
          this.value > this.numberMax ||
          this.value < this.numberMin
        )
      },
      numPrecision() {
        const { value, step, getPrecision, precision } = this
        const stepPrecision = getPrecision(step)
        if (precision !== undefined) {
          if (stepPrecision > precision) {
            console.warn(
              '[Element Warn][InputNumber]precision should not be less than the decimal places of step'
            )
          }
          return precision
        } else {
          return Math.max(getPrecision(value), stepPrecision)
        }
      },
      controlsAtRight() {
        return this.controls && this.controlsPosition === 'right'
      },
      _elFormItemSize() {
        return (this.elFormItem || {}).elFormItemSize
      },
      inputNumberSize() {
        return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size
      },
      inputNumberDisabled() {
        return this.disabled || !!(this.elForm || {}).disabled
      },
      displayValue() {
        if (this.userInput !== null) {
          return this.userInput
        }
        let currentValue = this.currentValue
        if (typeof currentValue === 'number') {
          if (this.precision !== undefined) {
            currentValue = currentValue.toFixed(this.precision)
          }
        }
        return currentValue
      },
    },
    watch: {
      value: {
        handler(value) {
          let newVal = value === undefined ? value : value
          if (newVal !== undefined) {
            if (isNaN(newVal)) {
              return
            }

            if (this.stepStrictly) {
              const stepPrecision = this.getPrecision(this.step)
              const precisionFactor = Math.pow(10, stepPrecision)
              newVal =
                (Math.round(newVal / this.step) * precisionFactor * this.step) /
                precisionFactor
            }

            if (this.precision !== undefined) {
              newVal = this.toPrecision(newVal, this.precision)
            }
          }
          // if (newVal >= this.max) newVal = this.max
          // if (newVal <= this.min) newVal = this.min
          this.currentValue = newVal
          this.userInput = null
          this.$emit('input', newVal)
        },
        immediate: true,
      },
      thousandsNumber(val) {
        if (val) {
          this.currentValue = val
        }
      },
    },
    mounted() {
      let innerInput = this.$refs.input.$refs.input
      innerInput.setAttribute('role', 'spinbutton')
      innerInput.setAttribute('aria-valuemax', this.max)
      innerInput.setAttribute('aria-valuemin', this.min)
      innerInput.setAttribute('aria-valuenow', this.currentValue)
      innerInput.setAttribute('aria-disabled', this.inputNumberDisabled)
    },
    updated() {
      if (!this.$refs || !this.$refs.input) return
      const innerInput = this.$refs.input.$refs.input
      innerInput.setAttribute('aria-valuenow', this.currentValue)
    },
    methods: {
      toPrecision(value = 0, precision) {
        const num = Number(value)
        if (precision === undefined) precision = this.numPrecision

        // return num

        return parseFloat(
          Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision)
        )
      },
      getPrecision(value) {
        if (value === undefined) return 0
        const valueString = value.toString()
        const dotPosition = valueString.indexOf('.')
        let precision = 0
        if (dotPosition !== -1) {
          precision = valueString.length - dotPosition - 1
        }
        return precision
      },
      /**
       * 加法
       * @param val 值
       * @param step 步进
       */
      _increase(val, step) {
        // if (typeof val !== 'number' && val !== undefined)
        //   return this.currentValue

        const precisionFactor = Math.pow(10, this.numPrecision)
        // Solve the accuracy problem of JS decimal calculation by converting the value to integer.

        return this.toPrecision(
          (precisionFactor * val + precisionFactor * step) / precisionFactor
        )
      },
      /**
       * 减法
       * @param val 值
       * @param step 步进
       */
      _decrease(val, step) {
        // if (typeof val !== 'number' && val !== undefined)
        //   return this.currentValue

        const precisionFactor = Math.pow(10, this.numPrecision)

        return this.toPrecision(
          (precisionFactor * val - precisionFactor * step) / precisionFactor
        )
      },
      increase() {
        if (this.inputNumberDisabled || this.maxDisabled) return

        const value = this.value || 0
        const newVal = this._increase(value, this.step)
        this.setCurrentValue(newVal)
      },
      decrease() {
        if (this.inputNumberDisabled || this.minDisabled) return
        const value = this.value || 0
        const newVal = this._decrease(value, this.step)

        this.setCurrentValue(newVal)
      },
      handleBlur(event) {
        if (!event.target.value) {
          event.target.value = 0
          this.$emit('input', event.target.value)
        } else if (this.thousandsNumber) {
          this.currentValue = this.thousandsNumber
        }
        this.$emit('blur', event)
      },
      handleFocus(event) {
        if (event.target.value == 0) {
          event.target.value = ''
          this.$emit('input', '')
        } else {
          this.currentValue = this.value
        }

        this.$emit('focus', event)
      },
      setCurrentValue(newVal) {
        const oldVal = this.currentValue
        if (typeof newVal === 'number' && this.precision !== undefined) {
          newVal = this.toPrecision(newVal, this.precision)
        }
        // if (newVal >= this.max) newVal = this.max
        // if (newVal <= this.min) newVal = this.min
        // if (oldVal === newVal) return
        this.userInput = null

        this.$emit('input', newVal)
        this.$emit('change', newVal, oldVal)
        this.currentValue = newVal
      },
      handleInput(value) {
        this.userInput = value
      },
      handleInputChange(value) {
        const newVal = value === '' ? undefined : value
        if (!isNaN(newVal) || value === '') {
          this.setCurrentValue(newVal)
        }
        this.userInput = null
      },
      select() {
        this.$refs.input.select()
      },
    },
  }
</script>
<style lang="scss" scoped>
  .el_home {
    display: flex;
    align-items: center;
    width: 100%;
    .unit {
      font-size: inherit;
      margin-right: 8px;
    }
  }
  .showCompanys-filtercurrency {
    margin: 18px 0;
  }
</style>
