<template>
  <view class="u-tree-node">
    <view class="u-tree-node-content" :style="{ paddingLeft: depth * indent + 'rpx' }" @click="toggle">
      <up-icon
        v-if="hasChildren"
        class="u-tree-node-toggle"
        :name="isExpanded ? collapseIcon : expandIcon"
        :size="iconSize"
      />
      <view v-else class="u-tree-node-toggle u-tree-node-toggle--placeholder"></view>
      <up-checkbox
        v-if="showCheckbox"
        usedAlone
        :size="checkboxSize"
        :checked="node.checked"
        @change="toggleCheck"
        style="margin-right: 10px;"
      />
      <!-- #ifdef MP-WEIXIN -->
      <text class="u-tree-node-label" :class="labelClass">{{ node[props.label] }}</text>
      <!-- #endif -->
      <!-- #ifndef MP-WEIXIN -->
      <slot :node="node" :data="node" :level="depth + 1" :expanded="isExpanded" :checked="!!node.checked" :disabled="isDisabled">
        <text class="u-tree-node-label" :class="labelClass">{{ node[props.label] }}</text>
      </slot>
      <!-- #endif -->
    </view>
    <view
      v-if="hasChildren && isExpanded"
      class="u-tree-node-children"
    >
      <TreeNode
        v-for="child in node[props.children]"
        :key="child[props.nodeKey]"
        :node="child"
        :props="props"
        :show-checkbox="showCheckbox"
        :check-strictly="checkStrictly"
        :expand-on-click-node="expandOnClickNode"
        :highlight-current="highlightCurrent"
        :current-node-key="currentNodeKey"
        :indent="indent"
        :icon-size="iconSize"
        :checkbox-size="checkboxSize"
        :expand-icon="expandIcon"
        :collapse-icon="collapseIcon"
        :depth="depth + 1"
        @node-click="$emit('node-click', $event)"
        @check-change="$emit('check-change', $event)"
      >
        <template #default="slotProps">
          <slot name="default" v-bind="slotProps"></slot>
        </template>
      </TreeNode>
    </view>
  </view>
</template>

<script>
import TreeNode from './tree-node.vue';

export default {
  name: 'tree-node',
  components: { TreeNode },
  props: {
    node: {
      type: Object,
      required: true
    },
    props: {
      type: Object,
      required: true
    },
    showCheckbox: {
      type: Boolean,
      default: false
    },
    checkStrictly: {
      type: Boolean,
      default: false
    },
    expandOnClickNode: {
      type: Boolean,
      default: true
    },
    highlightCurrent: {
      type: Boolean,
      default: false
    },
    currentNodeKey: {
      type: [String, Number],
      default: ''
    },
    indent: {
      type: [String, Number],
      default: 32
    },
    iconSize: {
      type: [String, Number],
      default: 14
    },
    checkboxSize: {
      type: [String, Number],
      default: 16
    },
    expandIcon: {
      type: String,
      default: 'play-right-fill'
    },
    collapseIcon: {
      type: String,
      default: 'arrow-down-fill'
    },
    depth: {
      type: Number,
      default: 0
    }
  },
  computed: {
    hasChildren() {
      return this.node[this.props.children] && this.node[this.props.children].length > 0;
    },
    isExpanded() {
      return this.node.expanded === undefined ? false : this.node.expanded;
    },
    isDisabled() {
      const disabledKey = this.props.disabled || 'disabled';
      return !!this.node[disabledKey];
    },
    isCurrent() {
      if (!this.highlightCurrent || this.currentNodeKey === '' || this.currentNodeKey === null || this.currentNodeKey === undefined) {
        return false;
      }
      return String(this.node[this.props.nodeKey]) === String(this.currentNodeKey);
    },
    labelClass() {
      return {
        'u-tree-node-label--current': this.isCurrent,
        'u-tree-node-label--disabled': this.isDisabled
      };
    }
  },
  emits: ['node-click', 'check-change'],
  methods: {
    toggle() {
      if (this.isDisabled) return;
      if (this.expandOnClickNode && this.hasChildren) {
        this.node.expanded = !this.node.expanded;
      }
      this.$emit('node-click', this.node);
    },
    toggleCheck(checked) {
      this.node.checked = checked;
      if (!this.checkStrictly) {
        this.updateChildCheckStatus(this.node, checked);
        this.updateParentCheckStatus(this.node);
      }
      this.$emit('check-change', this.node, checked);
    },
    updateChildCheckStatus(node, checked) {
      if (node[this.props.children]) {
        node[this.props.children].forEach((child) => {
          child.checked = checked;
          this.updateChildCheckStatus(child, checked);
        });
      }
    },
    updateParentCheckStatus(node) {
      let parent = this.$parent;
      while (parent && parent.node) {
        const allChecked = parent.node[this.props.children].every((child) => child.checked);
        parent.node.checked = allChecked;
        parent = parent.$parent;
      }
    }
  }
};
</script>

<style scoped>
.u-tree-node-content {
  display: flex;
  flex-direction: row;
  align-items: center;
  min-height: 72rpx;
  padding-right: 20rpx;
}

.u-tree-node-toggle {
  margin-right: 8rpx;
  flex-shrink: 0;
}

.u-tree-node-toggle--placeholder {
  width: 14px;
}

.u-tree-node-label {
  flex: 1;
  font-size: 28rpx;
  color: #333;
}

.u-tree-node-label--current {
  color: #2667E9;
  font-weight: 600;
}

.u-tree-node-label--disabled {
  color: #c0c4cc;
}
</style>
