<template>
  <div
    v-show="node.visible"
    ref="node"
    class="ibps-tree-node"
    :class="{ 'is-expanded': expanded,
              'is-current': node.isCurrent,
              'is-hidden': !node.visible,
              'is-checked': !node.disabled && node.checked }"
    role="treeitem"
    name="IbpsTreeNode"
    @click.stop="handleClick"
  >
    <div class="ibps-tree-node__content" :style="{ 'padding-left': (node.level - 1) * indent + 'px' }">
      <span :class="[{ 'is-leaf': node.isLeaf, expanded: !node.isLeaf && node.expanded }, 'ibps-tree-node__expand-icon', iconClass ? iconClass : 'ibps-icon ibps-icon-caret-right']" @click.stop="handleExpandIconClick" />

      <span v-if="checkboxVisible" class="ibps-checkbox" @click.stop="handleCheckChange(!node.checked)">
        <span class="ibps-checkbox__input" :class="[{'is-indeterminate': node.indeterminate, 'is-checked': node.checked, 'is-disabled': !!node.disabled}]">
          <span class="ibps-checkbox__inner" />
        </span>
      </span>

      <span v-if="radioVisible" class="ibps-radio" @click.stop="handleRadioChange(!node.checked)">
        <span v-if="!node.checked" class="ibps-radio__input" :class="[{'is-checked': node.checked, 'is-disabled': !!node.disabled}]">
          <span class="ibps-radio__inner" />
        </span>
        <span v-else class="ibps-radio__input" :class="[{'is-disabled': !!node.disabled}]">
          <div class="ibps-radio__inner ibps-radio__wrapper">
            <div class="ibps-radio__round" />
          </div>
        </span>
      </span>

      <span v-if="node.loading" class="ibps-tree-node__loading-icon ibps-icon ibps-icon-loading" />

      <template v-if="node.icon && node.icon.length > 0">
        <image v-if="node.icon.indexOf('/') !== -1" class="ibps-tree-node__icon" :src="node.icon" mode="widthFix" />
        <span v-else class="ibps-tree-node__icon" :class="node.icon" />
      </template>

      <span class="ibps-tree-node__label">{{ node.label }}</span>
    </div>
    <div v-if="!renderAfterExpand || childNodeRendered" v-show="expanded" class="ibps-tree-node__children" role="group">
      <ibps-tree-node
        v-for="cNodeId in node.childNodesId"
        :key="getNodeKey(cNodeId)"
        :node-id="cNodeId"
        :render-after-expand="renderAfterExpand"
        :show-checkbox="showCheckbox"
        :show-radio="showRadio"
        :check-only-leaf="checkOnlyLeaf"
        :indent="indent"
        :icon-class="iconClass"
      />
    </div>
  </div>
</template>

<script>
import { getNodeKey } from './tool/util.js'

export default {
  name: 'ibps-tree-node',

  componentName: 'IbpsTreeNode',

  props: {
    nodeId: [Number, String],
    renderAfterExpand: {
      type: Boolean,
      default: true
    },
    checkOnlyLeaf: {
      type: Boolean,
      default: false
    },
    showCheckbox: {
      type: Boolean,
      default: false
    },
    showRadio: {
      type: Boolean,
      default: false
    },
    indent: Number,
    iconClass: String
  },

  data() {
    return {
      node: null,
      expanded: false,
      childNodeRendered: false,
      oldChecked: null,
      oldIndeterminate: null
    }
  },

  inject: ['tree'],

  computed: {
    checkboxVisible() {
      if (this.checkOnlyLeaf) {
        return this.showCheckbox && this.node.isLeaf
      }

      return this.showCheckbox
    },
    radioVisible() {
      if (this.checkOnlyLeaf) {
        return this.showRadio && this.node.isLeaf
      }

      return this.showRadio
    }
  },

  watch: {
    'node.indeterminate'(val) {
      this.handleSelectChange(this.node.checked, val)
    },
    'node.checked'(val) {
      this.handleSelectChange(val, this.node.indeterminate)
    },
    'node.expanded'(val) {
      this.$nextTick(() => {
        this.expanded = val
      })
      if (val) {
        this.childNodeRendered = true
      }
    }
  },

  created() {
    if (!this.tree) {
      throw new Error('Can not find node\'s tree.')
    }

    this.node = this.tree.store.nodesMap[this.nodeId]

    if (this.node.expanded) {
      this.expanded = true
      this.childNodeRendered = true
    }

    const props = this.tree.props || {}
    const childrenKey = props['children'] || 'children'
    this.$watch(`node.data.${childrenKey}`, () => {
      this.node.updateChildren()
    })

    if (this.tree.accordion) {
      // uni.$on(`${this.tree.elId}-tree-node-expand`, node => {
      //   if (this.node.id !== node.id && this.node.level === node.level) {
      //     this.node.collapse()
      //   }
      // })
    }
  },

  beforeDestroy() {
    this.$parent = null
  },

  methods: {
    getNodeKey(nodeId) {
      const node = this.tree.store.root.getChildNodes([nodeId])[0]
      return getNodeKey(this.tree.nodeKey, node.data)
    },

    handleSelectChange(checked, indeterminate) {
      if (this.oldChecked !== checked && this.oldIndeterminate !== indeterminate) {
        if (this.checkOnlyLeaf && !this.node.isLeaf) return

        const allNodes = this.tree.store._getAllNodes()
        this.tree.$emit('check-change', {
          node: this.node,
          data: this.node.data,
          checked,
          indeterminate,
          checkedall: allNodes.every(item => item.checked)
        })
      }

      if (!this.expanded && this.tree.expandOnCheckNode && checked) {
        this.handleExpandIconClick()
      }

      this.oldChecked = checked
      this.indeterminate = indeterminate
    },

    handleClick() {
      this.tree.store.setCurrentNode(this.node)
      this.tree.$emit('current-change', {
        node: this.node,
        data: this.tree.store.currentNode ? this.tree.store.currentNode.data : null,
        currentNode: this.tree.store.currentNode
      })
      this.tree.currentNode = this.node

      if (this.tree.expandOnClickNode) {
        this.handleExpandIconClick()
      }

      if (this.tree.checkOnClickNode && !this.node.disabled) {
        if (this.checkOnlyLeaf) {
          this.showCheckbox && this.node.isLeaf && this.handleCheckChange(!this.node.checked)
          this.showRadio && this.node.isLeaf && this.handleRadioChange(!this.node.checked)
        } else {
          this.showCheckbox && this.handleCheckChange(!this.node.checked)
          this.showRadio && this.handleRadioChange(!this.node.checked)
        }
      }

      this.tree.$emit('node-click', this.node, this.tree, this)
    },

    handleExpandIconClick() {
      if (this.node.isLeaf) return

      if (this.expanded) {
        this.tree.$emit('node-collapse', this.node)
        this.node.collapse()
      } else {
        this.node.expand()
        this.tree.$emit('node-expand', this.node)

        if (this.tree.accordion) {
          // uni.$emit(`${this.tree.elId}-tree-node-expand`, this.node)
        }
      }
    },

    handleCheckChange(checked) {
      if (this.node.disabled) return

      if (this.checkboxVisible) {
        this.node.setChecked(checked, !(this.tree.checkStrictly || this.checkOnlyLeaf))

        this.$nextTick(() => {
          this.tree.$emit('check', {
            node: this.node,
            data: this.node.data,
            checkedNodes: this.tree.store.getCheckedNodes(),
            checkedKeys: this.tree.store.getCheckedKeys(),
            halfCheckedNodes: this.tree.store.getHalfCheckedNodes(),
            halfCheckedKeys: this.tree.store.getHalfCheckedKeys()
          })
        })

        return
      }

      this.node.setRadioChecked(checked)
      this.tree.$emit('radio-change', {
        node: this.node,
        data: this.node.data,
        checked
      })
    },

    handleRadioChange(checked) {
      if (this.node.disabled) return

      this.node.setRadioChecked(checked)
      this.tree.$emit('radio-change', {
        data: this.node.data,
        checked
      }, this.tree, this)
    }
  }
}
</script>
