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

    :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 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"
        position="bottom"
        get-container="body"
        @opened="openedPopup"
        @close="handleClose"
      >
        <ibps-picker-toolbar
          :cancel-button-text="cancelButtonText"
          :confirm-button-text="confirmButtonText"
          @cancel="onCancel"
          @confirm="onConfirm"
        />
        <div class="ibps-popup-wrapper">
          <ibps-tree
            ref="tree"
            :tree-data="treeData"
            :props="props"
            :node-key="valueKey"
            :show-radio="!multiple"
            :show-checkbox="multiple"
            @check="handleCheck"
            @radio-change="handleRadioChange"
          />
        </div>
      </van-popup>
    </template>
  </van-field>
</template>
<script>
import { findTreeData } from '@/api/platform/cat/type'
import { isDef } from 'vant/lib/utils'
import FieldMixin from '@/mixins/field'
import TreeUtils from '@/utils/tree'
import IbpsPickerToolbar from '@/components/ibps-picker-toolbar'
import IbpsTree from '@/components/ibps-tree/index.vue'

export default {
  components: {
    IbpsPickerToolbar,
    IbpsTree
  },
  mixins: [FieldMixin],
  props: {
    categoryKey: {
      type: String
    },
    store: { // 存储类型 对应[多选]有效，array 数组。string 字符串类型
      type: String,
      default: 'string',
      validator: function(value) {
        return ['array', 'string'].indexOf(value) !== -1
      }
    },
    storeSeparator: { // 存储值分割符，对于设置字符串类型的分隔符
      type: String,
      default: ','
    },
    displayMode: { // 显示模式 path 、name
      type: String,
      default: 'name',
      validator: function(value) {
        return ['name', 'path'].indexOf(value) !== -1
      }
    },
    multiple: { // 是否多选
      type: Boolean,
      default: false
    },
    valueKey: {
      type: String,
      default: 'id'
    },
    labelKey: {
      type: String,
      default: 'name'
    },
    cancelButtonText: String,
    confirmButtonText: String
  },
  data() {
    return {
      showPopup: false,
      loading: false,
      treeData: [],
      props: {
        children: 'children',
        label: 'name'
      },
      selectedLabel: '',
      selectData: null,
      selected: []
    }
  },
  computed: {
    showClear() {
      return this.clearable && this.$utils.isNotEmpty(this.value) && isDef(this.value) && this.editable
    }
  },
  watch: {
    value: {
      handler(val, oldVal) {
        if (val !== oldVal) {
          this.initSelectData()
          this.setSelected()
          this.validate()
        }
      },
      immediate: true
    }
  },
  created() {
    this.loadTreeData()
  },
  methods: {
    loadTreeData() {
      findTreeData({ 'categoryKey': this.categoryKey }).then(response => {
        const data = response.data || []

        const treeData = TreeUtils.transformToTreeFormat(data, {
          idKey: 'id',
          parentIdKey: 'parentId',
          childrenKey: 'children'
        })

        this.treeData = treeData.map((d) => {
          if (d.parentId === '-1') { d.disabled = true }
          return d
        })
        this.initSelectData()
        this.setSelected()
      }).catch(() => {
      })
    },
    initSelectData() {
      this.selectData = this.multiple ? this.getArrayValue() : this.value
    },
    setSelected() {
      if (this.$utils.isEmpty(this.treeData)) {
        return
      }
      if (this.multiple) {
        const result = []

        const selectedLabel = []
        if (Array.isArray(this.selectData)) {
          this.selectData.forEach(value => {
            const node = this.getNodeData(value)
            if (node) {
              selectedLabel.push(this.displayMode === 'name' ? node.label : node.path)
              result.push(node)
            }
          })
        }
        this.selected = result
        this.selectedLabel = selectedLabel.join(',')
      } else {
        const node = this.getNodeData(this.value)
        if (node) {
          this.selected = node
          this.selectedLabel = this.displayMode === 'name' ? node.label : node.path
        } else {
          this.selectedLabel = ''
        }
      }
    },
    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.valueKey] === value) {
              node = {
                label: labelData,
                value: child[this.valueKey],
                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
    },

    handleRadioChange({ data, checked }, tree) {
      if (this.multiple) { return }
      if (data.parentId === '-1') return
      this.selectData = checked ? data[this.valueKey] : ''
    },
    handleCheck(data) {
      const { checkedNodes } = data
      const nodes = checkedNodes
      this.selectData = nodes.map((node) => node[this.valueKey])
    },

    onClick() {
      if (!this.editable) {
        return
      }
      this.loading = true
      this.initSelectData()
      this.showPopup = true
    },
    onRightIconClick() {
      this.showClear ? this.onClear() : this.onClick()
    },
    onClear() {
      this.$emit('input', '')
    },
    openedPopup() {
      if (this.$refs.tree) {
        this.$refs.tree.setCheckedKeys(this.multiple ? this.selectData : [this.selectData], true)
      }
    },
    handleClose() {
      this.showPopup = false
    },
    onCancel() {
      this.showPopup = false
      this.$emit('cancel', this)
    },
    onConfirm() {
      this.showPopup = false
      const val = this.getStoreValue(this.selectData)
      this.$emit('input', val)
      this.$emit('confirm', this)
    },
    getStoreValue(val) {
      if (this.multiple) {
        if (this.store === 'string') {
          return this.$utils.isNotEmpty(val) ? val.join(this.storeSeparator) : ''
        } else {
          return val || []
        }
      } else {
        return val
      }
    }

  }
}
</script>

