<template>
  <div :class="['hanzo-counter', size === 'small' ? 'hanzo-counter__small' : '', theme === 'pre'?'hanzo-counter__pre':'']">
    <button :class="[ 'hanzo-counter__minus', minusDisabled ? 'van-stepper__minus--disabled' : '' ]" @click="onChange('minus')"/>
    <input 
        v-if="!this.disabled && !this.disableInput"
        type="number" 
        class="hanzo-counter__input"
        :readonly="this.disabled || this.disableInput"      
        :value="currentValue"
        @input="onInput"
        @focus="onFocus"
        @blur="onBlur"
        :style="{ width: `${ inputWidth }px` }"
    />
    <div 
      v-else
      :class="[size==='small'?'hanzo-counter__text_small':'hanzo-counter__text_big']" 
      :style="{ width: inputWidth }"
    >{{currentValue}}</div>
    <button :class="[ 'hanzo-counter__plus', plusDisabled ? 'hanzo-counter__plus--disabled' : '' ]" @click="onChange('plus')"/>
  </div>
</template>

<script>
import { isDef } from "../../common/utils/index";
export default {
  name: "h-counter",
  props: {
    value: null,
    integer: Boolean,
    disabled: Boolean,
    inputWidth: String,
    asyncChange: Boolean,
    disableInput: Boolean,
    size: String,
    theme: String,
    min: {
      type: [String, Number],
      default: 0
    },
    max: {
      type: [String, Number],
      default: Infinity
    },
    step: {
      type: [String, Number],
      default: 1
    },
    defaultValue: {
      type: [String, Number],
      default: 0
    }
  },
  data() {
    const value = this.range(
      isDef(this.value) ? this.value : this.defaultValue
    );
    if (value !== +this.value) {
      this.$emit("input", value);
    }

    return {
      currentValue: value
    };
  },

  computed: {
    minusDisabled() {
      return this.disabled || this.currentValue <= this.min;
    },

    plusDisabled() {
      return this.disabled || this.currentValue >= this.max;
    }
  },

  watch: {
    value(val) {
      if (val !== this.currentValue) {
        this.currentValue = this.format(val);
      }
    },

    currentValue(val) {
      this.$emit("input", val);
      this.$emit("change", val);
    }
  },

  methods: {
    // filter illegal characters
    format(value) {
      value = String(value).replace(/[^0-9.-]/g, "");
      return value === "" ? 0 : this.integer ? Math.floor(value) : +value;
    },

    // limit value range
    range(value) {
      return Math.max(Math.min(this.max, this.format(value)), this.min);
    },

    onInput(event) {
      const { value } = event.target;
      const formatted = this.format(value);

      if (this.asyncChange) {
        if (+value !== formatted) {
          event.target.value = formatted;
        }
        this.currentValue = formatted;
      } else {
        event.target.value = this.currentValue;
        this.$emit("input", formatted);
        this.$emit("change", formatted);
      }
    },

    onChange(type) {
      
      if (this[`${type}Disabled`]) {
        this.$emit("overlimit", type);
        return;
      }

      const diff = type === "minus" ? -this.step : +this.step;
      const value = Math.round((this.currentValue + diff) * 100) / 100;

      if (!this.asyncChange) {
        this.currentValue = this.range(value);
      } else {
        if ( type === "minus" ) {
          this.$emit("minus", this.currentValue);
        } else {
          this.$emit("plus", this.currentValue);
        }
        this.$emit("input", value);
      }
    },

    onFocus(event) {
      this.$emit("focus", event);
    },

    onBlur(event) {
      this.currentValue = this.range(this.currentValue);
      this.$emit("blur", event);

      // fix edge case when input is empty and min is 0
      if (this.currentValue === 0) {
        event.target.value = this.currentValue;
      }
    }
  }
};
</script>

<style lang="less">
@import "./index.less";
</style>