import Vue from 'vue'
import './SntNumberField.scss'

const REGEXP_NUMBER = /^-?(?:\d+|\d+\.\d+|\.\d+)(?:[eE][-+]?\d+)?$/
const REGEXP_DECIMALS = /\.\d*(?:0|9){10}\d*$/
const normalizeDecimalNumber = (value, times = 100000000000) => (
  REGEXP_DECIMALS.test(String(value)) ? (Math.round(value * times) / times) : value
)

export default Vue.extend({
  name: 'SntNumberField',
  props: {
    value: {
      type: Number,
      default: undefined
    },
    min: {
      type: Number,
      default: -Infinity
    },
    max: {
      type: Number,
      default: Infinity
    },
    step: {
      type: Number,
      default: 1
    },
    controls: Boolean,
    center: Boolean
  },
  data () {
    return {
      newValue: NaN
    }
  },
  computed: {
    increasable () {
      return this.$_.isNaN(this.value) || this.value < this.max
    },
    decreasable () {
      return this.$_.isNaN(this.value) || this.value > this.min
    }
  },
  watch: {
    value: {
      immediate: true,
      handler (newValue, oldValue) {
        if (
          // Avoid triggering change event when created
          !(this.$_.isNaN(newValue) && typeof oldValue === 'undefined')
          // Avoid infinite loop
          && newValue !== this.newValue
        ) {
          this.setValue(newValue)
        }
      }
    }
  },
  methods: {
    change (e) {
      const value = e.target.value
      this.setValue(value)
    },
    paste (e) {
      const clipboardData = e.clipboardData || window.clipboardData
      if (clipboardData && !REGEXP_NUMBER.test(clipboardData.getData('text'))) {
        e.preventDefault()
      }
    },
    decrease () {
      if (this.decreasable) {
        let { value } = this
        if (this.$_.isNaN(value)) {
          value = 0
        }
        this.setValue(normalizeDecimalNumber(value - this.step))
      }
    },
    increase () {
      if (this.increasable) {
        let { value } = this
        if (this.$_.isNaN(value)) {
          value = 0
        }
        this.setValue(normalizeDecimalNumber(value + this.step))
      }
    },
    setValue (value) {
      const oldValue = this.newValue
      let newValue = Number(value)
      if (!this.$_.isNaN(newValue)) {
        if (this.min <= this.max) {
          newValue = Math.min(this.max, Math.max(this.min, newValue))
        } else {
          newValue = this.min
        }
      }
      this.newValue = newValue
      if (newValue === oldValue) {
        this.$refs.input.value = String(newValue)
      }
      this.$emit('input', newValue)
    }
  },
  template: `
    <div
      class="snt-number-field"
      :class="{
        'snt-number-input--controls': controls,
        'snt-number-input--center': center,
      }">
      <button
        v-if="controls"
        class="snt-number-input__button snt-number-input__button--minus"
        type="button"
        tabindex="-1"
        @click="decrease($event)"
      />
      <input
        ref="input"
        :value="newValue"
        :min="min"
        :max="max"
        type="number"
        class="snt-number-field__input"
        onkeypress="return event.charCode >= 48 && event.charCode <= 57"
        autocomplete="off"
        @change="change($event)"
        @paste="paste($event)" />
      <button
        v-if="controls"
        class="snt-number-input__button snt-number-input__button--plus"
        type="button"
        tabindex="-1"
        @click="increase($event)"
      />
    </div>
  `
})
