<template>
  <li
    class="vc-tree-node"
    role="treeitem"
  >
    <div
      class="vc-tree-node__content"
      @click.stop="onNodeClick"
    >
      <span
        :class="{
          'no-visibility': !hasChildren,
          'is--expanded': expanded
        }"
        class="vc-tree-node__arrow-btn"
        @click.stop="expandIconClick"
      >
        <i
          class="vc-icon-right vc-tree-node__arrow-icon"
        />
      </span>
      <VcCheckbox
        v-if="selectable"
        hand-update
        :disabled="disabled"
        :indeterminate="partialChecked"
        :checked="checked"
        class="vc-tree-node__checkbox"
      />
      <slot
        name="label"
        :node="node"
      >
        <span
          v-if="nodeIcon"
          :class="nodeIcon"
          class="vc-tree-node__content-icon icon-lg"
        />
        <span class="vc-tree-node__content-label">
          {{ nodeLabel }}
        </span>
      </slot>
    </div>
    <ul
      v-if="hasChildren && expanded"
      class="vc-tree-node__children"
      role="group"
    >
      <VcTreeNode
        v-for="item in children"
        :key="item[nodeKey]"
        :node="item"
        :config="config"
        :disabled="disabled"
        :expanded-keys="expandedKeys"
        :selected-keys="selectedKeys"
        :selectable="selectable"
        @node-toggle="onToggleChildrenNode"
        @node-change="onChangeChildrenNode"
      >
        <template
          v-if="$slots['label']"
          #label="data"
        >
          <slot
            name="label"
            :node="data.node"
          />
        </template>
      </VcTreeNode>
    </ul>
  </li>
</template>

<script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */
import { defineComponent, PropType } from 'vue'
import VcCheckbox from '@/components/VcCheckbox/VcCheckbox.vue'
import { VcTreeActionKeys, VcTreeChangeEvent, VcTreeConfig, VcTreeNodeType } from '@/components/VcTree/VcTree.types'

const DEFAULT_CONFIG = {
  valueKey: 'key',
  labelKey: 'label',
  iconKey: 'icon',
  childrenKey: 'children'
}

export default defineComponent({
  name: 'VcTreeNode',
  components: { VcCheckbox },
  props: {
    isRoot: {
      type: Boolean,
      default: false
    },
    node: {
      type: Object as PropType<VcTreeNodeType>,
      default: () => ({})
    },
    expandedKeys: {
      type: Object as PropType<VcTreeActionKeys>,
      default: () => ({})
    },
    selectedKeys: {
      type: Object as PropType<VcTreeActionKeys>,
      default: () => ({})
    },
    selectable: {
      type: Boolean,
      default: true
    },
    config: {
      type: Object as PropType<VcTreeConfig>,
      default: () => ({ ...DEFAULT_CONFIG })
    },
    disabled: {
      type: Boolean,
      default: true
    }
  },
  emits: [
    'node-change',
    'node-toggle'
  ],
  data () {
    return {
      localNodeData: this.node as VcTreeNodeType
    }
  },
  computed: {
    childrenKey (): string {
      return this.config.childrenKey || DEFAULT_CONFIG.childrenKey
    },
    children (): VcTreeNodeType[] {
      return this.localNodeData[this.childrenKey] || []
    },
    nodeKey (): string | number {
      return this.config.valueKey || DEFAULT_CONFIG.valueKey
    },
    nodeKeyValue (): any {
      const _key = this.nodeKey
      return this.node[_key]
    },
    nodeIcon (): string {
      const _key = this.config.iconKey || DEFAULT_CONFIG.iconKey
      return this.node[_key]
    },
    nodeLabel (): string {
      const _key = this.config.labelKey || DEFAULT_CONFIG.labelKey
      return this.node[_key]
    },
    hasChildren (): boolean {
      return !!this.children.length
    },
    expanded (): boolean {
      return !!(this.expandedKeys && this.expandedKeys[this.nodeKeyValue] === true)
    },
    checked (): boolean {
      return !!this.node.checked
    },
    partialChecked (): boolean {
      if (this.selectable) {
        let childPartialSelected = false
        if (this.children) {
          childPartialSelected = this.checkNodeChildren(this.node)
        }
        return childPartialSelected && !this.checked
      }

      return false
    }
  },
  watch: {
    node (val) {
      this.localNodeData = val
    }
  },
  created () {
    this.setLocalData()
  },
  methods: {
    setLocalData () {
      this.localNodeData.parent = this.getParentNode()
    },
    checkNodeChildren (node: VcTreeNodeType): boolean {
      let _res = false
      if (!node[this.childrenKey]?.length) {
        return _res
      }
      for (const child of node[this.childrenKey]) {
        if (child.checked || _res) {
          _res = true
          break
        } else {
          _res = this.checkNodeChildren(child)
        }
      }
      return _res
    },
    onChangeChildrenNode (event: VcTreeChangeEvent): void {
      this.$emit('node-change', {
        node: event.node,
        check: event.check
      })
    },
    getParentNode (): VcTreeNodeType {
      return (this.$parent as any)?.node
    },
    onNodeClick (): void {
      if (this.selectable) {
        const _check = !this.checked
        const _node = this.localNodeData
        this.$emit('node-change', {
          node: _node,
          check: _check
        })
      }
    },
    expandIconClick (): void {
      this.$emit('node-toggle', this.node)
    },
    onToggleChildrenNode (node: VcTreeNodeType): void {
      this.$emit('node-toggle', node)
    }
  }
})
</script>
<style lang="scss" scoped>
.vc-tree-node {
  @apply transition-all duration-300 mb-1;
  &__content {
    @apply flex items-center cursor-pointer leading-4;
  }
  &__checkbox {
    @apply mr-2;
  }
  &__arrow-btn {
    @apply w-5 h-5 mr-2 flex flex-shrink-0 items-center justify-center cursor-pointer rounded-full text-inactive-elements hover:bg-active-elements-bg--focus transition-all duration-200;
    &.no-visibility {
      visibility: hidden;
    }
    &.is--expanded {
      transform: rotate(90deg);
    }
  }
  &__arrow-btn &__arrow-icon{
    @apply text-xl font-medium text-inactive-elements hover:text-active-elements--focus;
  }
  &__content-icon {
    @apply mr-2 text-active-elements;
  }
  &__content-label {
    @apply text-sm py-1 min-h-6.5;
  }
  &__children {
    @apply pl-6;
  }
}
</style>
<style lang="scss">
[dir='rtl'] {
  .vc-tree {
    &-node {
      &__checkbox {
        @apply ml-2 mr-0;
      }
      &__arrow-btn {
        @apply mr-0 ml-2;
        transform: rotate(180deg);
        &.is--expanded {
          transform: rotate(90deg);
        }
      }
      &__content-icon {
        @apply mr-0 ml-2;
      }
      &__children {
        @apply pl-2 pr-6;
      }
    }
  }
}
</style>
