<template>
  <view v-if="isFromReadonly" class="ml-number-input is-readonly">
    <view class="ml-number-input-readonly-content">{{ inpVal }}</view>
  </view>
  <view v-else-if="!editable && (platformEnv.isWXMP || platformEnv.isQWMP)" class="ml-number-input not-edit" :class="[className || '', {'is-right': align === 'right', 'is-border': border}]">
    <view class="ml-number-input-simulate">
      <text v-if="inpVal">{{ inpVal }}</text>
      <text v-else class="ml-number-input-placeholder">{{ placeholder }}</text>
    </view>
  </view>
  <view v-else class="ml-number-input" :class="[{'is-right': align === 'right', 'is-border': border, 'is-controls': controls, 'is-disabled': disabled, 'is-clear': clearable && inpVal}, className]">
    <view v-if="controls" class="ml-number-input-minus-btn" @click="minusEvent">
      <ml-icon name="minus" />
    </view>
    <input
      class="ml-number-input-inp"
      v-model="inpVal"
      :type="type === 'integer' ? 'number' : 'digit'"
      :class="[className || '', {'is-right': align === 'right', 'is-border': border}]"
      autocomplete="off"
      :placeholder="placeholder"
      :maxlength="maxLength"
      :disabled="disabled"
      @blur="blurEvent"
      @input="inputEvent" />
    <view v-if="clearable && !disabled && inpVal" class="ml-number-input-clear-icon" @click.stop="clearEvent">
      <ml-icon name="delete-filling"></ml-icon>
    </view>
    <view v-if="controls" class="ml-number-input-plus-btn" @click="plusEvent">
      <ml-icon name="add" />
    </view>
  </view>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import XEUtils from 'xe-utils'
import MaliUtils from '../../../utils'

function eqEmptyNull (value: any) {
  return value === '' || XEUtils.eqNull(value)
}

export default defineComponent({
  name: 'MlNumberInput',
  options: {
    virtualHost: true
  },
  props: {
    modelValue: [String, Number],
    align: String,
    border: Boolean,
    type: String,
    min: [String, Number],
    max: [String, Number],
    step: [String, Number],
    controls: Boolean,
    placeholder: {
      type: String,
      default: '请输入'
    },
    disabled: Boolean,
    editable: {
      type: Boolean,
      default: true
    },
    clearable: Boolean,
    className: String
  },
  inject: {
    form: {
      from: 'mlForm',
      default: null
    }
  },
  data () {
    return {
      platformEnv: MaliUtils.getPlatformEnv(),
      inpVal: '' as any,
      updateModel: false
    }
  },
  computed: {
    isFromReadonly () {
      const form: any = this.form
      return form ? form.readonly : false
    },
    maxLength () {
      if (this.type === 'integer') {
        return this.maxNum ? `${this.maxNum}`.length : 9
      }
      return this.maxNum ? (`${this.maxNum}`.length + 3) : 12
    },
    minNum () {
      if (XEUtils.isNumber(this.min) || this.min) {
        return XEUtils.toNumber(this.min || 0)
      }
      return null
    },
    maxNum () {
      if (XEUtils.isNumber(this.max) || this.max) {
        return XEUtils.toNumber(this.max)
      }
      return null
    },
    stepNum () {
      if (XEUtils.isNumber(this.step) || this.step) {
        return XEUtils.toNumber(this.step) || 1
      }
      return 1
    }
  },
  watch: {
    modelValue (val) {
      if (!this.updateModel) {
        this.inpVal = val
      }
      this.updateModel = false
    }
  },
  created () {
    this.updateValue(this.modelValue)
  },
  methods: {
    updateValue (value: any) {
      this.inpVal = eqEmptyNull(value) ? '' : String(XEUtils.toNumber(value))
    },
    checkValue  () {
      const numVal: any = XEUtils.toNumber(XEUtils.toValueString(this.inpVal).slice(0, this.maxLength))
      if (this.minNum !== null && (numVal < this.minNum)) {
        this.updateModel = true
        this.inpVal = this.minNum
        this.$emit('update:modelValue', this.minNum)
        return { status: false, value: this.minNum }
      }
      if (this.maxNum !== null && (numVal > this.maxNum)) {
        this.updateModel = true
        this.inpVal = this.maxNum
        this.$emit('update:modelValue', this.maxNum)
        return { status: false, value: this.maxNum }
      }
      // 如果是空值，则不处理
      if (eqEmptyNull(this.inpVal) && eqEmptyNull(this.modelValue)) {
        return { status: true, value: this.inpVal }
      }
      if (this.type === 'integer' && !/^-?[0-9]+$/.test(numVal)) {
        const value = XEUtils.toInteger(numVal)
        this.updateModel = true
        this.inpVal = value
        this.$emit('update:modelValue', value)
        return { status: false, value: value }
      }
      if (`${numVal}` !== this.inpVal) {
        this.updateModel = true
        this.inpVal = numVal
        this.$emit('update:modelValue', numVal)
        return { status: false, value: numVal }
      }
      if (`${numVal}` !== `${this.modelValue}`) {
        this.updateModel = true
        this.inpVal = numVal
        this.$emit('update:modelValue', numVal)
        return { status: false, value: numVal }
      }
      return { status: true, value: numVal }
    },
    minusEvent () {
      const numVal = this.type === 'integer' ? XEUtils.toInteger(this.inpVal) : XEUtils.toNumber(this.inpVal)
      let value = XEUtils.subtract(numVal, this.stepNum)
      if (this.maxNum !== null) {
        value = Math.min(this.maxNum, value)
      }
      if (this.minNum !== null) {
        value = Math.max(this.minNum, value)
      }
      if (`${value}` !== `${this.modelValue}`) {
        this.inpVal = value
        this.$emit('update:modelValue', value)
        this.$emit('change', { value })
      }
    },
    plusEvent () {
      const numVal = this.type === 'integer' ? XEUtils.toInteger(this.inpVal) : XEUtils.toNumber(this.inpVal)
      let value = XEUtils.add(numVal, this.stepNum)
      if (this.minNum !== null) {
        value = Math.max(this.minNum, value)
      }
      if (this.maxNum !== null) {
        value = Math.min(this.maxNum, value)
      }
      if (`${value}` !== `${this.modelValue}`) {
        this.inpVal = value
        this.$emit('update:modelValue', value)
        this.$emit('change', { value })
      }
    },
    blurEvent () {
      this.checkValue()
      this.$emit('blur', { value: this.inpVal })
    },
    inputEvent () {
      this.$emit('update:modelValue', this.inpVal)
      this.$emit('change', {})
    },
    clearEvent () {
      this.inpVal = ''
      this.inputEvent()
      this.$emit('clear', { value: this.inpVal })
      this.$emit('change', {})
    }
  }
})
</script>

<style lang="scss">
.ml-number-input {
  flex-grow: 1;
  display: flex;
  flex-direction: row;
  .ml-number-input-placeholder {
    color: $ml-input-color-placeholder;;
  }
  .ml-number-input-readonly-content {
    padding: 20rpx 4rpx;
  }
  .ml-number-input-simulate {
    padding: 0 10rpx;
    height: 70rpx;
    line-height: 70rpx;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    background: #ffffff;
  }
  &.is-right {
    .ml-number-input-inp,
    .ml-number-input-simulate {
      text-align: right;
    }
  }
  &.is-border,
  &.is-controls {
    .ml-number-input-clear-icon {
      border: 1px solid #e5e5e5;
      border-left: 0;
    }
    .ml-number-input-inp,
    .ml-number-input-simulate {
      border: 1px solid #e5e5e5;
      border-radius: $ml-border-radius;
    }
  }
  &.is-controls {
    .ml-number-input-inp,
    .ml-number-input-simulate {
      border-radius: 0;
    }
    .ml-number-input-inp {
      text-align: center;
    }
  }
  .ml-number-input-inp,
  .ml-number-input-simulate {
    font-size: $ml-base-font-size;
    width: 100%;
    height: 70rpx;
    padding: 0 10rpx;
  }
  .ml-number-input-inp::-webkit-outer-spin-button,
  .ml-number-input-inp::-webkit-inner-spin-button {
    -webkit-appearance: none;
  }
  .ml-number-input-clear-icon {
    width: 60rpx;
    display: flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    background: #fff;
    color: $ml-input-clear-icon-color;
    font-size: $ml-input-clear-icon-font-size;
    border-radius: 0 $ml-border-radius $ml-border-radius 0;
  }
  .ml-number-input-inp {
    outline: 0;
    border: 0;
  }
  .ml-number-input-minus-btn,
  .ml-number-input-plus-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 80rpx;
    border: 1px solid #e5e5e5;
    font-size: 36rpx;
    padding: 0 16rpx;
    background: #F2F2F6;
  }
  .ml-number-input-minus-btn {
    border-right: 0;
    border-radius: $ml-border-radius 0 0 $ml-border-radius;
  }
  .ml-number-input-plus-btn {
    border-left: 0;
    border-radius: 0 $ml-border-radius $ml-border-radius 0;
  }
  &.is-clear {
    .ml-number-input-inp {
      padding-right: 0;
      border-right: 0;
    }
  }
}
</style>
