<template>
  <van-field
    ref="input"
    v-model="inputValue"
    :label="label"
    :name="name"
    :size="size"
    :placeholder="placeholder"
    :border="border"
    :disabled="disabled"
    :required="required"
    :clearable="clearable"
    :clickable="clickable"
    :is-link="isLink"
    :error="error"
    :error-message="errorMessage"

    :arrow-direction="arrowDirection"
    :label-class="labelClass"
    :label-width="labelWidth"
    :label-align="labelAlign"
    :input-align="inputAlign"
    :error-message-align="errorMessageAlign"
    :autosize="autosize"
    :left-icon="leftIcon"
    :right-icon="rightIcon"
    :icon-prefix="iconPrefix"
    :rules="editable?rules:null"
    readonly
    @click-input="onClick"
  >
    <template #label>
      {{ label }}<van-icon v-if="desc && descPosition==='lableIcon'" name="warning" class="ibps-dialog-icon" @click="$action.descDialog({ title:label, message:desc })" />
    </template>
    <template v-if="editable" #right-icon>
      <van-icon
        v-if="showClear"
        name="clear"
        class="van-field__clear"
        @click.native.stop="onRightIconClick"
      />
      <van-icon
        v-else
        :name="showPopup?'arrow-up':'arrow-down'"
        @click.native.stop="onClick"
      />
      <van-popup
        v-model="showPopup"
        get-container="body"
        position="bottom"
        @opened="openedPopup"
        @close="handleClose"
      >
        <ibps-picker-toolbar
          :title="title"
          :cancel-button-text="cancelButtonText"
          :confirm-button-text="confirmButtonText"
          @cancel="onCancel"
          @title="onTitleClick"
          @confirm="onConfirm"
        />
        <div class="ibps-popup-inner">
          <ibps-tree
            v-if="showPopup"
            ref="tree"
            :tree-data="treeData"
            :node-key="nodeKey"
            :props="props"
            :show-radio="!multiple"
            :show-checkbox="multiple"
            :check-only-leaf="checkOnlyLeaf"
            :default-checked-keys="defaultCheckedKeys"
            check-strictly
            @check="handleCheck"
            @radio-change="handleRadioChange"
          />
        </div>
      </van-popup>
    </template>
    <template v-if="multiple && $utils.isNotEmpty(selected)" #input>
      <div class="van-field__control">
        <!-- <van-tag
          v-for="(item,index) in selected"
          :key="item[nodeKey]+index"
          type="primary"
          class="ibps-tag-span"
          size="medium"
          plain
        >{{ displayMode === 'name'?item.label:item.path }}</van-tag> -->
        <van-tag
          v-for="(item,index) in selected.slice(0,num)"
          :key="item[nodeKey]+index"
          size="medium"
          :color="color"
          :text-color="textColor"
          class="ibps-tag-span ibps-mr-8"
        >
          <template #default>
            <div class="ibps-ellipsis">{{ displayMode === 'name'?item.label:item.path }}</div>
          </template>
        </van-tag>
        <van-tag
          v-if="selected.length>num"
          :color="color"
          :text-color="textColor"
        >+{{ selected.length-num }}</van-tag>
      </div>
    </template>
  </van-field>
</template>

<script>
import { findByTypeKey } from '@/api/platform/cat/dictionary'
import { isDef } from 'vant/lib/utils'
import FieldMixin from '@/mixins/field'
import TreeUtils from '@/utils/tree'
import { remoteRequest } from '@/utils/remote'
import IbpsTree from '@/components/ibps-tree/index.vue'
import IbpsPickerToolbar from '@/components/ibps-picker-toolbar'

export default {
  name: 'ibps-dictionary',
  components: {
    IbpsPickerToolbar,
    IbpsTree
  },
  mixins: [FieldMixin],
  props: {
    typeKey: { // 数据字典类型key
      type: String
    },
    data: {
      type: Array
    },
    multiple: { // 是否多选
      type: Boolean,
      default: false
    },
    labelKey: {
      type: String,
      default: 'name'
    },
    store: { // 存储类型 对应[多选]有效，array 数组。string 字符串类型
      type: String,
      default: 'string',
      validator: function(value) {
        return ['array', 'string'].indexOf(value) !== -1
      }
    },
    storeSeparator: { // 存储值分割符，对于设置字符串类型的分隔符
      type: String,
      default: ','
    },
    selectMode: { // 选值模式 leaf、any
      type: String,
      default: 'any',
      validator: function(value) {
        return ['any', 'leaf'].indexOf(value) !== -1
      }
    },
    displayMode: { // 显示模式 path 、name
      type: String,
      default: 'name',
      validator: function(value) {
        return ['name', 'path'].indexOf(value) !== -1
      }
    },
    separator: { // 树形选项分隔符
      type: String,
      default: '/'
    },
    readonlyText: { // 只读样式 【text original】
      type: String,
      default: 'original',
      validator(val) {
        return ['original', 'text'].indexOf(val) > -1
      }
    },
    warningText: {
      type: String,
      default: '请选择叶子节点'
    },
    cancelButtonText: String,
    confirmButtonText: String,
    color: {
      type: String,
      default: '#D6EAFE'
    },
    textColor: {
      type: String,
      default: '#3396FB'
    }
  },
  data() {
    return {
      showPopup: false,
      props: {
        children: 'children',
        label: this.labelKey
      },
      nodeKey: 'key',
      defaultCheckedKeys: [],
      selectData: null,
      treeData: [],
      selected: [],

      radioTitle: '',
      num: 3 // 默认最多显示3个选项
    }
  },
  computed: {
    showClear() {
      return this.clearable && this.$utils.isNotEmpty(this.value) && isDef(this.value) && this.editable
    },
    title() {
      if (this.multiple) {
        const length = this.selectData ? this.selectData.length : 0
        return length > 0 ? this.$t('components.checkbox.title', { length: length }) : ''
      } else if (this.radioTitle) {
        return this.radioTitle
      } else {
        return this.inputValue
      }
    },
    cacheOptions() {
      const arr = this.options
      if (!arr || arr.length === 0) { return {} }
      const cacheOptions = {}
      for (let i = 0; i < arr.length; i++) {
        const option = arr[i]
        if (option instanceof String) {
          cacheOptions[option] = {
            [this.labelKey]: option
          }
        } else {
          cacheOptions[option[this.nodeKey] ] = option
        }
      }
      return cacheOptions
    },
    checkOnlyLeaf() {
      return this.selectMode === 'leaf'
    }
  },
  watch: {
    value: {
      handler(val, oldVal) {
        this.initSelectData()
        this.setSelected()
        this.validate()
      },
      immediate: true
    },
    typeKey: {
      handler(val, oldVal) {
        if (this.$utils.isEmpty(this.data)) {
          this.loadTreeData()
        } else {
          this.treeData = JSON.parse(JSON.stringify(this.data)) || []
        }
      },
      immediate: true
    }

  },
  created() {
    this._getNumByWidth()
  },
  methods: {
    _getNumByWidth() {
      const width = document.documentElement.clientWidth
      if (width >= 375) this.num = 3
      else this.num = 2
    },
    loadTreeData() {
      const typeKey = this.typeKey
      if (!typeKey) { return }
      remoteRequest('dictionary', typeKey, () => {
        return this.getRemoteFunc(typeKey)
      }, this.repeatRequest).then(response => {
        const data = response.data
        this.treeData = TreeUtils.transformToTreeFormat(data)
        this.setSelected()
        this.validate()
      }).catch(() => {
      })
    },
    getRemoteFunc(typeKey) {
      return new Promise((resolve, reject) => {
        findByTypeKey({ typeKey: typeKey })
          .then(response => {
            resolve(response)
          }).catch((error) => {
            reject(error)
          })
      })
    },
    getArrayValue() {
      if (this.store === 'string') {
        return this.$utils.isNotEmpty(this.value) ? this.value.split(this.storeSeparator) : []
      } else {
        return this.value || []
      }
    },
    getStoreValue(val) {
      if (this.multiple) {
        if (this.store === 'string') {
          return this.$utils.isNotEmpty(val) ? val.join(this.storeSeparator) : ''
        } else {
          return val || []
        }
      } else {
        return val
      }
    },
    initSelectData() {
      this.selectData = this.multiple ? this.getArrayValue() : this.value
    },
    setSelected() {
      if (this.$utils.isEmpty(this.treeData)) {
        this.selected = []
        this.inputValue = ''
        return
      }

      const result = []
      const inputValue = []
      if (this.multiple) {
        if (Array.isArray(this.selectData)) {
          this.selectData.forEach(value => {
            const node = this.getNodeData(value)
            if (node) {
              inputValue.push(this.displayMode === 'name' ? node.label : node.path)
              result.push(node)
            }
          })
        }
      } else {
        const node = this.getNodeData(this.value)
        if (node) {
          inputValue.push(this.displayMode === 'name' ? node.label : node.path)
          result.push(node)
        }
      }
      this.selected = result
      this.inputValue = inputValue.join(',')
    },
    getNodeData(value) {
      let node = null
      if (Array.isArray(this.treeData)) {
        const traverse = (arr, lablePrefix = []) => {
          for (let i = 0; i < arr.length; i++) {
            const child = arr[i]
            let labelData = child[this.labelKey]
            if (typeof this.labelKey !== 'string') {
              labelData = this.labelKey(child)
            }
            if (child[this.nodeKey] === value) {
              node = {
                label: labelData,
                value: child[this.nodeKey],
                path: [...lablePrefix, labelData].join(this.separator),
                data: child
              }
              break
            } else if (child.children && child.children.length > 0) {
              traverse(child.children, [...lablePrefix, labelData])
            }
          }
        }
        traverse(this.treeData)
      }
      return node
    },

    onClick() {
      if (!this.editable) { return }
      this.initSelectData()
      this.defaultCheckedKeys = this.multiple ? this.selectData : [this.selectData]
      this.showPopup = true
    },
    openedPopup() {
      // if (this.$refs.tree) {
      //   this.$refs.tree.setCheckedKeys(this.multiple ? this.selectData : [this.selectData], true)
      // }
    },
    handleClose() {
      this.radioTitle = ''
      this.showPopup = false
    },

    onRightIconClick() {
      this.showClear ? this.onClear() : this.onClick()
    },
    onClear() {
      this.$emit('input', '')
    },
    onTitleClick() {

    },
    handleRadioChange({ data, checked }, tree) {
      if (this.multiple) { return }
      if (typeof this.allowSelection === 'function' && !this.allowSelection(data, tree)) {
        return false
      }
      // if ((this.selectMode === 'leaf' && !data.isLeaf) || (this.selectMode === 'leaf' && data.isLeaf === false)) {
      //   this.$notify({
      //   type: 'warning',
      //   message: this.warningText
      // })
      //   return false
      // }

      this.selectData = checked ? data[this.nodeKey] : ''
      this.radioTitle = data.name
    },
    handleCheck(data) {
      const { checkedNodes } = data
      let nodes = []
      switch (this.showCheckedStrategy) {
        case 'parent':
          nodes = this.getTreeCheckedParentNodes()
          break
        case 'child':
          nodes = checkedNodes.filter(({ children }) => !(children && children.length))
          break
        default:
          nodes = checkedNodes
          break
      }
      this.selectData = nodes.map((node) => node[this.nodeKey])
    },
    getTreeCheckedParentNodes() {
      const checkedNodes = []
      const traverse = (node) => {
        const childNodes = node.root ? node.root.childNodes : node.childNodes
        childNodes.forEach(child => {
          if (child.checked && !child.isLeaf) {
            checkedNodes.push({
              label: child.data.label,
              value: child.data.value
            })
          } else {
            traverse(child)
          }
        })
      }
      traverse(this.$refs.tree.store)
      return checkedNodes
    },
    onCancel() {
      this.handleClose()
      this.$emit('cancel', this)
    },
    onConfirm() {
      this.handleClose()
      const val = this.getStoreValue(this.selectData)
      this.$emit('input', val)
      this.$emit('confirm', this)
    }
  }
}
</script>
