<template>
  <div>
    <span
      v-if="showonly"
      v-text="valueInner"
      style="word-break: break-all;"
      :class="mdata&&(mdata.name==='name'||mdata.name==='title')?'text-bold':''"
    ></span>
    <span
      v-if="showonly&&mdata&&mdata.suffix&&mdata.suffix.length&&valueInner&&valueInner.length"
      v-text="mdata.suffix"
      class="text-grey-7"
    ></span>
    <q-input
      v-model="valueInner"
      :debounce="debounce"
      v-bind="$attrs"
      v-if="!showonly"
      :type="mdata&&mdata.isNumber?'number':$attrs.type"
      @keydown.up="doKeyDown($event,'up')"
      @keydown.down="doKeyDown($event,'down')"
      @keydown.esc="showMenu=false;"
      @keydown.enter="doKeyDown($event,'enter');"
      @input="input"
      @focus="completion && !itemsInner.length && query(valueInner)"
      @blur="checkInput();$emit('blur',$event)"
      :autogrow="mdata&&mdata.maxLength>64"
      :class="inputClass"
    >
      <template #append>
        <span
          v-if="mdata&&mdata.suffix&&mdata.suffix.length"
          v-text="mdata.suffix"
          class="text-subtitle1"
        ></span>
        <q-btn
          v-if="completion"
          round
          dense
          flat
          icon="play_arrow"
          size="0.5em"
          color="grey-5"
          class="select-btn cursor-pointer"
          @click.stop="showMenu=!showMenu"
          :class="showMenu?'extend':''"
        />
        <slot name="append" />
      </template>
      <q-menu fit v-if="completion" v-model="showMenu" no-focus>
        <q-list>
          <q-item
            clickable
            v-close-popup
            v-for="(v,index) in itemsInner"
            @click="selectItem(v)"
            manual-focus
            :focused="selctIndex===index"
            :key="index"
          >
            <q-item-section v-text="v[titleKey]"></q-item-section>
          </q-item>
          <q-item v-if="!itemsInner||!itemsInner.length">
            <q-item-section class="text-grey-6">无数据</q-item-section>
          </q-item>
        </q-list>
      </q-menu>
    </q-input>
    <div class="row" v-if="!showonly&&mdata">
      <div class="col">
        <div v-for="(v,k) in error" :key="k">
          <q-icon name="error_outline" class="text-negative q-mr-xs" size="1.2em" />
          <span v-text="v.msg" class="text-negative"></span>
        </div>
        <div v-if="mdata.desc" class="text-caption text-grey-8" v-text="'说明：'+mdata.desc"></div>
      </div>
      <div v-if="mdata.isNumber&&mdata.min!=null&&mdata.max!=null">
        <span
          class="text-caption text-grey-7"
          title="输入数值的范围"
          v-text="'数值范围: '+(mdata.min?(mdata.min+'-'):'')+mdata.max"
        ></span>
      </div>
      <div v-if="!mdata.isNumber">
        <span
          class="text-caption"
          :class="error.maxLenth||error.minLenth?'text-negative':'text-primary'"
          v-text="strLen?strLen:0"
        ></span>
        <span class="text-caption text-grey-7">/</span>
        <span
          class="text-caption text-grey-7"
          title="可输入字符的长度范围"
          v-text="(mdata.minLength?(mdata.minLength+'-'):'')+mdata.maxLength+'个字符'"
        ></span>
      </div>
    </div>
  </div>
</template>
<script>
import _ from 'underscore'
import KybMdata from '../kyb-mdata.js'
import Rule from '../rule'
import { extend } from 'quasar'
import { validator } from 'kyb-extend'

export default {
  mixins: [KybMdata],
  name: 'kyb-input',
  model: {
    prop: 'value',
    event: 'input'
  },
  props: {
    name: String,
    mdata: Object,
    completion: { type: Boolean, default: false }, // 是否补全提示
    queryUrl: String,
    itemKey: { type: String, default: '_id' }, // 唯一Id字段
    titleKey: { type: String, default: 'name' }, // 显示字段
    valueKey: { type: String, default: '_id' }, // 值的字段

    items: { type: Array, default: () => [] },
    value: String,
    showonly: Boolean,
    debounce: String
  },
  data: function() {
    return {
      showMenu: false,
      valueInner: this.value,
      selctIndex: 0,
      itemsInner: []
    }
  },
  computed: {
    inputClass() {
      let c = []
      c.push(Object.keys(this.error).length === 0 ? 'bg-white' : 'bg-red-2')
      return c.join(' ')
    },
    error() {
      let len = this.strLen
      let err = {}
      if (this.mdata) {
        if (this.mdata.maxLength > 0 && len > this.mdata.maxLength) {
          err['maxLenth'] = {
            msg: `输入字符不能大于${this.mdata.maxLength}个字符`
          }
        }
        if (this.mdata.minLength > 0 && len < this.mdata.minLength) {
          err['maxLenth'] = {
            msg: `输入字符不能小于${this.mdata.minLength}个字符`
          }
        }
        if (this.mdata.isNumber) {
          if (isNaN(this.valueInner)) {
            err['number'] = {
              msg: `必须输入数字`
            }
          }
          let v = parseFloat(this.valueInner)
          if (this.mdata.max > 0 && v > this.mdata.max) {
            err['max'] = {
              msg: `输入数值不能大于${this.mdata.max}`
            }
          }
          if (this.mdata.min > 0 && v < this.mdata.min) {
            err['min'] = {
              msg: `输入数值不能小于${this.mdata.min}`
            }
          }
        }
        this.mdata.otherRules &&
          (typeof this.mdata.otherRules === 'string' ? this.mdata.otherRules.split(',') : this.mdata.otherRules).forEach(ruleStr => {
            try {
              Rule.execute({
                rule: ruleStr,
                field: this.mdata,
                value: this.valueInner
              })
            } catch (e) {
              err[ruleStr] = {
                msg: e.message
              }
            }
          })
        // check type
        this.mdata.validatorType &&
          this.mdata.validatorType.forEach(v => {
            let isOk = validator.check(v, this.valueInner)
            if (!isOk) {
              err['v'] = { msg: validator.checkMap[v].desc }
            }
          })
      }
      this.$emit('error', err)
      return err
    },
    strLen() {
      return this.valueInner ? this.valueInner.length : 0
    }
  },
  watch: {
    items(old) {
      if (this.completion) {
        this.showMenu = true
        this.itemsInner = old
      }
    },
    mdata(old) {
      this.mdata = old
      this.fixMData()
    },
    value(newValue) {
      this.valueInner = newValue
    }
  },
  created() {
    // this.showMenu = this.completion
    this.fixMData()
    this.items.forEach(element => {
      if (_.isString(element)) {
        let v = {}
        v[this.itemKey] = element
        v[this.titleKey] = element
        v[this.valueKey] = element
        this.itemsInner.push(v)
      } else {
        this.itemsInner.push(element)
      }
    })
  },
  methods: {
    fixMData() {
      if (this.mdata) {
        this.mdata.maxLength || (this.mdata.maxLength = 64)
      }
    },
    async input($event) {
      this.$emit('input', $event)
      this.checkInput()
      await this.query($event)
    },
    checkInput() {},
    async query(value) {
      if (this.completion) {
        if (this.entity || this.queryUrl) {
          let param = extend({}, this.queryParam)
          param.pageSize = 10
          param.pageNo = 1
          param.___keyword = value || this.valueInner || ''
          param.___keyword_field = this.titleKey
          let re = await this.queryDataAtLinkEntity(param)
          this.itemsInner = re.data.items
          this.selctIndex = 0
          // console.log(this.itemsInner);
          this.showMenu = true
        }
      }
    },
    async selectItem(v) {
      v || (v = this.itemsInner[this.selctIndex])
      if (!v) return
      this.$emit('input', v[this.titleKey])
      this.$emit('selected', v)
    },
    async doKeyDown($event, type) {
      console.log($event)
      if (type === 'up' || type === 'down') {
        if (!this.itemsInner || !this.itemsInner.length) {
          await this.query()
        }
        this.showMenu = true
        this.selctIndex =
          (this.selctIndex + (type === 'up' ? -1 : 1)) % this.itemsInner.length
      } else if (type === 'enter') {
        if (this.showMenu) {
          await this.selectItem()
          $event.preventDefault()
          $event.stopPropagation()
        } else {
          if (this.mdata && this.mdata.maxLength > 64) {
          } else {
            this.$emit('submit', $event)
          }
        }
      }
    }
  }
}
</script>
<style lang="stylus">
.select-btn {
  transition: all 0.5s;
}

.select-btn.extend {
  transform: rotate(90deg);
}
</style>
