<template>
  <n-options ref="options" v-model="isFocus" v-bind="{disabled, state, pasterOptions, options, virtual, maxHeight, autoClose: false, builders, multiple}"
             @click="onOptionSelect">
    <n-form-refer class="n-select" v-model="isFocus" v-bind="{name, values, state, multiple, size, border,  disabled, placeholder,clearable, builder: builders.value}"
                  @u-update="onReferUpdateValues"></n-form-refer>
  </n-options>
</template>
<script>
import NOptions from '@uif/next/lib/components/options'
import NFormRefer from '@uif/next/lib/components/form-refer'
import {propsArray, spliceOrPush, inArray, prop, isSameFormValue} from '@uif/next/lib/utils/tools'
import {getSearchState} from '_common/SearchState'

export default {
  inheritAttrs: false,
  name: 'n-select',
  components: {
    NOptions,
    NFormRefer
  },
  props: {
    // 表单名
    name: prop.string(),
    // 初始值 multiple 下 value 需为 Array
    value: {
      type: [Array, String, Number, Boolean],
      default: ''
    },
    // 多选
    multiple: prop.boolean(),
    // 选中的option列表
    values: prop.array(),
    // 选项
    options: prop.array(),
    // 开启虚拟滚动
    virtual: prop.boolean(),
    // 禁用
    disabled: prop.boolean(),
    // 可删除
    clearable: prop.boolean(true),
    // 选择框提示文本
    placeholder: prop.string('请选择'),
    // 大小
    size: propsArray(['small', 'middle', 'large'], 'middle'),
    // 边框
    border: propsArray(['none', 'line', 'rect'], 'rect'),
    // 搜索
    search: {
      type: [Boolean, Object],
      default: false
    },
    // 下拉宽度 // 'auto', 'same'
    dropWidth: prop.stringNumber('auto'),
    // 自定义渲染
    builders: prop.object(() => ({
      value: null,
      header: null,
      option: null,
      footer: null,
      empty: null
    })),
    // 最大高度
    maxHeight: prop.stringNumber(270)
  },
  data () {
    const state = getSearchState(this.search)
    return {
      state,
      // 下拉框可见
      isFocus: false,
      nValue: state.toNValue(this.value, this.multiple)
    }
  },
  computed: {
    pasterOptions ({dropWidth}) {
      const sameWidth = inArray(['auto', 'same'], dropWidth)
      return {
        sameWidth,
        styles: {
          width: dropWidth + 'px',
          maxWidth: dropWidth === 'same' ? 'unset' : ''
        }
      }
    }
  },
  watch: {
    options (options) {
      this.state.updateOptions(options)
    },
    value () {
      this.onPropValueUpdate()
    },
    nValue (nValue) {
      if (this.value !== nValue) {
        this.$emit('input', nValue)
        this.$emit('update:value', nValue)
      }
    },
    isFocus (value) {
      value ? this.onFocus() : this.onBlur()
    }
  },
  created () {
    this.state.cacheOptions(this.values)
    this.state.updateOptions(this.options)
    this.onPropValueUpdate()
    this.$emit('u-bind', '$reSearch', this.reSearch)
  },
  methods: {
    // 点击选项
    onOptionSelect (option) {
      // 多选
      if (this.multiple) {
        spliceOrPush(this.nValue, option.value, value => isSameFormValue(value, option.value))
      } else {
        this.nValue = option.value
        this.state.set('value', this.nValue)
      }
      // 更新 values
      this.state.updateValuesByValue(this.values, this.nValue)
      this.$emit('u-update', this.nValue)
      if (!this.multiple) {
        this.isFocus = false
      }
    },
    // refer 点击删除按钮
    onReferUpdateValues (values) {
      this.nValue = this.state.toNValue(values.map(v => v.value), this.multiple)
      this.state.updateValuesByValue(this.values, this.nValue)
      this.$emit('u-update', this.nValue)
      // 非 focus 状态下 改变值 需要
      if (!this.isFocus) {
        this.$emit('u-change', this.nValue)
      }
      if (this.isFocus && !this.multiple) {
        this.isFocus = false
      }
    },
    // value更新 同步 nValue 和 values
    onPropValueUpdate () {
      this.nValue = this.state.toNValue(this.value, this.multiple)
      this.state.updateValuesByValue(this.values, this.nValue)
    },
    // focus回调
    onFocus () {
      this.state.onFocus(this.multiple, this.values)
      this.backup = this.state.getStringify(this.nValue)
      this.$emit('u-focus', this)
    },
    // blur回调
    onBlur () {
      const option = this.state.getBlurOption()
      if (option) {
        this.onOptionSelect(option)
      }
      this.state.onBlur()
      this.$emit('u-blur', this)
      if (this.backup !== this.state.getStringify(this.nValue)) {
        this.$emit('u-change', this.nValue)
      }
    },
    // 重新搜索
    reSearch (force) {
      if (force) {
        this.onReferUpdateValues([])
      }
      this.state.reSearch(force)
    }
  }
}
</script>
