<template>
  <div class="kyb-tree" :style="{paddingTop: hideToolbar?'0':'36px'}">
    <div v-if="!hideToolbar" class="toolbar q-pa-xs">
      <slot name="toolbar" v-bind="treeSelectedItem">
        <input
          v-if="!lazy"
          class="col-6 q-ml-xs q-mr-xs"
          style="width:110px;padding:2px;border-radius:3px;border:1px solid #ccc;"
          v-model="keyword"
          placeholder="输入关键字查询"
          @input="find()"
        />
        <!-- showRight是附加到下面的右侧侧滑面板的模型 -->
        <q-btn
          icon="vertical_align_center"
          title="折叠子项"
          flat
          dense
          size="0.85em"
          @click="openAll=!openAll;openItem(item)"
        >
          <q-tooltip>{{openAll?'展开所有':'折叠所有'}}</q-tooltip>
        </q-btn>
        <q-btn icon="refresh" v-if="entity" title="刷新数据" flat dense size="0.85em" @click="loadAll">
          <q-tooltip>刷新数据</q-tooltip>
        </q-btn>
        <q-btn
          :icon="isEdit?'lock_open':'lock'"
          :color="isEdit?'primary':'negative'"
          flat
          dense
          size="0.8em"
          @click="isEdit=!isEdit"
        >
          <q-tooltip>{{isEdit?'编辑模式':'只读模式'}}</q-tooltip>
        </q-btn>
        <q-btn v-if="isEdit" icon="add" color="primary" flat dense size="0.85em" @click="addItem()">
          <q-tooltip>添加子项</q-tooltip>
        </q-btn>
        <q-btn
          v-if="isEdit"
          icon="edit"
          color="primary"
          flat
          dense
          size="0.85em"
          @click="updateItem()"
        >
          <q-tooltip>修改名称</q-tooltip>
        </q-btn>
        <q-btn
          v-if="isEdit"
          icon="clear"
          color="negative"
          flat
          dense
          size="0.85em"
          @click="delItem()"
        >
          <q-tooltip>删除子项</q-tooltip>
        </q-btn>
      </slot>
    </div>
    <div v-if="showSelectList&&selectType!=='more'" v-text="selectOneShow"></div>
    <kyb-tree-item
      ref="root"
      class="fit scroll"
      is-node
      :lazy="lazy"
      :entity="entity"
      :is-edit="isEdit"
      :select-type="selectType"
      :item="item"
      :item-key="itemKey"
      :title-key="titleKey"
      :value-key="valueKey"
      :tree-selected-item="treeSelectedItem"
      :tree-obj="this"
      :is-root="true"
      @add-item="$emit('add-item', $event)"
      @select-item="selectItem"
      @del-item="delItem"
      @del-action="delAction"
      @save-to-server="saveToServer"
      @load-child="$emit('load-child', $event)"
      @item-change="itemChange"
      @mounted-item="mountedItem"
    >
      <template #icon="item">
        <slot name="icon" v-bind="item" />
      </template>
      <template #title="item">
        <slot name="title" v-bind="item" />
      </template>
      <template #edit="item">
        <slot name="edit" v-bind="item" />
      </template>
    </kyb-tree-item>
  </div>
</template>
<script>
/**
 * TODO: 1.拖动将节点移动另外的节点下。
 * TODO: 2.数和节点可以readOnly
 */
// import { uid } from 'quasar'
import _ from 'underscore'
import KybMdata from '../kyb-mdata.js'
import KybTreeItem from './kyb-tree-item'
// 递归执行所有子孙
import di from './di'

export default {
  mixins: [KybMdata],
  components: { KybTreeItem },
  name: 'kyb-tree',
  model: {
    prop: 'selectList',
    event: 'input'
  },
  props: {
    hideToolbar: Boolean,
    node: Object, // 节点数据
    list: Array, // 列表数据，需要封装为树形数据
    lazy: Boolean,
    showSelectList: Boolean, // 只读方式仅显示选择的列表
    selectType: { type: String, default: 'none' }, // 选中方式
    entity: String,
    queryParam: Object,
    selectList: { type: Array, default: () => [] }, // 已选中的对象id
    itemKey: { type: String, default: '_id' }, // 唯一Id字段
    titleKey: { type: String, default: 'name' }, // 显示字段
    valueKey: { type: String, default: '_id' }, // 值的字段
    autoLoad: { type: Boolean, default: true } // 是否自动加载远程数据
  },
  data: function() {
    return {
      isEdit: false,
      item: this.node
        ? this.node
        : { _id: '-1', name: '根节点', title: '根节点' },
      treeSelectedItem: null,
      selectValueItem: null,
      selectListInner: this.selectList ? [...this.selectList] : [],
      keyword: null,
      openAll: false,
      itemMap: {}
    }
  },
  watch: {
    keyword: function(old) {
      // console.log(old);
    },
    entity(old) {
      if (this.autoLoad) {
        this.loadAll()
      }
    },
    selectList(newVal) {
      // 重新设置树的值
      console.log('----- newVal:', newVal)
      if (!newVal) newVal = []
      // console.log('----- oldVal:', oldVal)
      // 如果是单选，就找到这个单选的对象，然后将其状态改为未选择
      if (this.selectType === 'one' && this.selectedOne) {
        this.selectedOne.setValueAction(false, false)
      }
      this.selectListInner = [...newVal]
      // console.log('----- isEqual:', isEqual)
      this.setValueList()
    },
    list(old) {
      this.setTreeData(old)
    }
  },

  created: async function() {
    if (this.list) {
      this.setTreeData(this.list)
    }
  },
  computed: {
    selectListInnerMap() {
      return Array.toMap(this.selectListInner)
    },
    selectOneShow() {
      let v = null
      if (this.selectList && this.selectList.length > 0) {
        let obj = this.itemMap[this.selectList[0]]
        if (obj) {
          v = obj.title || obj.name
        } else {
          v = this.selectList[0]
        }
      }
      return v
    }
  },
  async mounted() {
    if (this.autoLoad && this.entity) {
      await this.loadAll()
    }
    // console.log("aaaa:", this.$refs.root.$refs["item_2"]);
    this.$refs.root.selectItem() // 焦点默认房子root节点
    if (this.item && this.item.children && this.item.children.length) {
      this.$refs.root.toggle(true) // 如果有子节点就展开根节点
      // 如果是单选，并且已经选了值，就一直展开到选择的那一项
      if (
        this.selectType === 'one' &&
        this.selectList &&
        this.selectList.length > 0
      ) {
        // TODO
      }
    }
    this.setValueList()
  },
  methods: {
    // 递归循环的函数
    forAllChild: function(item, k) {
      k(item)
      if (item.children && item.children.length) {
        item.children.forEach(v => {
          this.forAllChild(v, k)
        })
      }
    },
    async find() {
      let isNotNull = this.keyword && this.keyword.length
      // 懒加载的情况
      if (this.entity && this.lazy) {
        await this.loadAll()
        return
      }

      let filteritem = obj => {
        if (
          isNotNull &&
          obj[this.titleKey] &&
          obj[this.titleKey]
            .toLowerCase()
            .indexOf(this.keyword.toLowerCase()) === -1
        ) {
          obj.$isHide = true
        } else {
          obj.$isHide = false
          obj.$isOpen = true
          if (isNotNull) {
            let parent = obj.$parent
            while (parent) {
              parent.$isHide = false
              parent = parent.$parent
            }
          }
        }
        if (obj.children && obj.children.length) {
          obj.children.forEach(v => {
            v.$parent = obj
            filteritem(v)
          })
        }
      }
      filteritem(this.item)
      this.$refs.root.$forceUpdate()
    },
    // 递归某一个子节点及子孙显示或隐藏
    openItem() {
      this.$refs.root.toggle(this.openAll, true)
      // 当前节点为选中节点
      this.selectItem(this.$refs.root)
    },
    selectItem(selectItem) {
      if (selectItem) {
        this.notDel = !selectItem.parent
        this.notUpdate = false
        this.notAdd = false

        this.treeSelectedItem = selectItem
        this.$emit('select-item', selectItem)
      }
    },
    sendInput() {
      this.$emit('input', this.selectListInner)
    },
    /**
     * 递归的方式, 选择对应的节点, 但不传递Input事件出去
     */
    setValueList() {
      // 单选的情况
      if (this.selectType === 'one') {
        if (!this.selectListInner || !this.selectListInner.length) return
        let obj = this.getNodeByKey(this.selectListInner[0])
        if (obj) {
          obj.setValueAction(false, true)
          this.selectedOne = obj
        }
        return
      }
      let map = Array.toMap(this.selectListInner)
      // 首先情况所有的选择
      this.$refs.root.setValueAction(false, false, true)
      di(this.$refs.root, { map }, (p, { map }) => {
        let hasChild = p.item.children && p.item.children.length
        if (p && p.item && map[p.item[this.itemKey]] && !hasChild) {
          p.setValueAction(false, true, true)
          delete map[p.item[this.itemKey]]
        }
      })
    },
    getNodeByKey: function(key) {
      let re = []
      di(this.$refs.root, { re, key }, (p, { re, key }) => {
        if (p && p.item && p.item[this.itemKey] === key) {
          re.push(p)
          return false
        }
      })
      return re.length > 0 ? re[0] : null
    },
    async loadAll() {
      if (!this.entity) {
        this.$q.showNotifi('需设置  entity')
        return
      }
      let l = this.queryParam ? this.queryParam : {}
      l.pageNo = 1
      l.pageSize = 5000
      if (this.lazy) l._pid = this.item._id
      if (this.lazy && this.keyword && this.keyword.length) {
        l.___keyword = this.keyword
        l.___keyword_field = this.titleKey
      }
      let param = _.map(
        l,
        (v, k) => encodeURIComponent(k) + '=' + encodeURIComponent(v)
      ).join('&')
      let url = await this.genBaseUrl(`/query?${param}`)
      let response = await this.$axios.get(url)

      this.setTreeData(response.data.items)
    },
    setTreeData(items) {
      let pidMap = {}
      let setChild = vv => {
        if (vv === null || vv === undefined) return
        if (pidMap[vv._id] && pidMap[vv._id].length) {
          vv.children = pidMap[vv._id]
          vv.children.forEach(setChild)
          vv.children = vv.children.sort((a, b) => (a.name > b.name ? 1 : -1))
        }
      }
      if (items && items.length) {
        this.itemMap = items.reduce((re, v) => {
          re[v._id] = v
          return re
        }, {})
        items.forEach(v => {
          pidMap[v.pid] || (pidMap[v.pid] = [])
          pidMap[v.pid].push(v)
        })
        setChild(this.item)
      } else {
        this.item.children = []
      }
      if (this.$refs.root) this.$refs.root.$forceUpdate()
    },
    addItem: async function(item) {
      if (this.treeSelectedItem) {
        // console.log(this.treeSelectedItem)
        this.treeSelectedItem.addItem()
        this.$refs.root.$forceUpdate()
        this.$forceUpdate()
        this.$emit('add-item', this.treeSelectedItem)
      }
    },
    // 删除等修改发生
    itemChange: function(type, eventObj) {
      this.$emit('item-change', type, eventObj)
      if (type === 'delChild') {
        // console.log(type, eventObj)
        // this.checkAllInput()
      }
    },
    mountedItem(obj) {
      // if (!this.selectListInner || !this.selectListInner.length) return
      // if (
      //   this.selectType === 'more' &&
      //   obj.item.children &&
      //   obj.item.children.length
      // ) {
      //   return
      // }
      // console.log(this.selectListInner, obj)
      // let value = obj.item[this.itemKey]
      // let indexOf = this.selectListInner.findIndex(v => v === value)
      // if (indexOf > -1) {
      //   obj.selectValueAction(false, true, true)
      // }
    },
    updateItem: function() {
      this.treeSelectedItem.updateItem()
    },
    saveToServer: async function(item) {},
    delToServer: async function(item, parent, indexOf) {
      if (this.entity) {
        await this.$axios.post(await this.genBaseUrl(`/del`), {
          _id: item._id
        })
        this.$q.showNotifi('删除成功')
      }
      this.deleteNode(item, parent, indexOf)
    },
    deleteNode: async function(item, parent, indexOf) {
      let isChangeSelect = this.treeSelectedItem === item
      parent.children.splice(indexOf, 1)
      if (!isChangeSelect) {
        return
      }
      let next = indexOf - 1,
        len = parent.children.length
      if (next < 0) {
        if (len > 0) {
          this.treeSelectedItem = parent.children[len - 1]
          this.treeSelectedItem.$parent = parent
        } else {
          this.treeSelectedItem = parent
        }
      } else {
        this.treeSelectedItem = parent.children[next]
        this.treeSelectedItem.$parent = parent
      }
      this.$emit('del-item', item)
    },
    // delItemAction: function(item, parent, indexOf) {
    //   if (item._id) {
    //     this.delToServer(item, item.$parent, indexOf)
    //   } else {
    //     this.deleteNode(item, item.$parent, indexOf)
    //   }
    // },
    delItem: function(item) {
      if (this.treeSelectedItem) {
        this.treeSelectedItem.delItem()
      }
    },
    delAction(item) {
      item.delAction(item)
    },

    /**
     * 选择所有选中的Ids
     */
    getSelectedIds(treeItem) {
      treeItem || (treeItem = this.$refs.root)
      const selectIds = []
      if (
        treeItem.selectStatus === 2 &&
        treeItem.item[this.valueKey] !== '-1'
      ) {
        selectIds.push(treeItem.item[this.valueKey])
      }
      treeItem.item.children &&
        treeItem.item.children.forEach((v, k) => {
          selectIds.splice(
            selectIds.length,
            0,
            ...this.getSelectedIds(treeItem.$refs['item_' + k][0])
          )
        })

      return selectIds
    }
  }
}
</script>
<style lang="stylus">
.kyb-tree {
  position: relative;
  overflow: hidden;
}

.kyb-tree .toolbar {
  border-bottom: 1px solid $grey-4;
  background: $grey-3;
  height: 36px;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  overflow: hidden;
}

.tree-content {
  overflow: auto;
}
</style>
