<template>
<div class="honjo-number">
  <el-popover placement="top-start" :title="text" trigger="manual" v-model="actualVisible" popperClass="honjo-number__popper">
    <el-input slot="reference" v-model="num" v-bind="props" class="honjo-number__input" @focus="focus = true" @blur="onBlur">
      <template slot="prepend" v-if="$slots.prepend"><slot name="prepend"></slot></template>
      <template slot="append" v-if="$slots.append"><slot name="append"></slot></template>
    </el-input>
  </el-popover>
  <div class="honjo-number__unit" v-if="unitText">{{unitText}}</div>
</div>
</template>

<script lang="ts">

import { Vue, Component, Prop, Ref, Emit, Watch } from 'vue-property-decorator'

function format (value: number, unit = '', precise: number | undefined) {
  if (isNaN(value)) return value
  let text = String(value)
  if (precise !== undefined) {
    text = Number(value).toFixed(precise)
  }
  const bit = text.indexOf('.') < 0 ? '' : text.substr(text.indexOf('.'))
  const f = text.replace(/\..*$/, '').split('').reverse().join('').replace(/(\d{3})\B/g, (_, c) => _ + ',').split('').reverse().join('') + bit
  return unit + f
}

function isUnregular (text = '') {
  if (text.endsWith('..')) return false
  if (text.endsWith('.')) return true
  if (text.indexOf('.') !== -1 && text.endsWith('0')) return true
  return false
}

function getBits (text: number | string) {
  const t = typeof text === 'number' ? String(text) : text
  const len = t.length
  const idx = t.indexOf('.')
  if (idx < 0) return 0
  return len - 1 - idx
}

function trim (text: number | string, precision = 0) {
  const t = typeof text === 'number' ? String(text) : text
  const len = t.length
  const idx = t.indexOf('.')
  if (idx < 0) return t
  if (precision <= 0) return t.slice(0, idx)
  return t.slice(0, idx + 1 + precision)
}

const unitTable = ['个', '十', '百', '千', '万', '十万', '百万', '千万', '亿', '十亿', '百亿', '千亿', '万亿']

@Component({
  components: { }
})
export default class HonjoNumber extends Vue {
  @Prop(Number) value!: number

  @Prop(Number) min!: number

  @Prop({ type: Boolean, default: false }) showActual!: boolean

  @Prop(Number) max!: number

  @Prop(Number) precision!: number

  @Prop(String) size!: 'large' | 'small' | 'medium'

  @Prop(Boolean) disabled!: boolean

  @Prop(String) placeholder!: string

  @Prop({ type: Boolean, default: true }) unit!: boolean

  @Emit() input (value: number | null) {}

  local = ''

  focus = false

  get num () {
    if (this.local) return this.local
    if (isNaN(this.value as any) || this.value === null) return ''
    let ret = +this.value
    if (this.max !== undefined) ret = Math.min(Number(this.max), ret)
    // if (this.min !== undefined) ret = Math.max(Number(this.min), ret)
    if ((this.precision || this.precision === 0) && this.precision >= 0 && getBits(ret) > this.precision) return ret.toFixed(this.precision)
    return String(ret)
  }

  set num (num: string) {
    if (isNaN(num as any)) return
    if (isUnregular(num)) {
      this.local = num
    } else {
      this.local = ''
    }
    if (num === '') {
      this.input(null)
    } else {
      let ret = Number(num)
      if (this.max !== undefined) ret = Math.min(Number(this.max), ret)
      // if (this.min !== undefined) ret = Math.max(Number(this.min), ret)
      if (this.precision && this.precision >= 0 && getBits(ret) > this.precision) ret = Number(trim(ret, this.precision))
      this.input(ret)
    }
  }

  set actualVisible (visible: boolean) {
    // do nothing
  }

  get actualVisible () {
    return this.focus && !this.disabled && !!this.text && this.showActual
  }

  get props () {
    return {
      min: this.min,
      max: this.max,
      precision: this.precision,
      size: this.size,
      disabled: this.disabled,
      placeholder: this.placeholder
    }
  }

  get text () {
    if (!this.num) return ''
    return format(Number(this.num), '', this.precision)
  }

  get unitText () {
    if (!this.num || !this.unit) return ''
    const text = Number(this.num).toFixed(0)
    return unitTable[text.length - 1]
  }

  get hiddenPopperCls () {
    const hidden = !this.text || this.disabled
    return hidden ? 'honjo-number__popper--hiden' : ''
  }

  onBlur () {
    this.focus = false
    let ret = this.value
    // if (this.max !== undefined) ret = Math.min(Number(this.max), ret)
    if (this.min !== undefined) ret = Math.max(Number(this.min), ret)
    if (ret !== this.value) {
      this.input(ret)
    }
  }
}
</script>

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

</style>
