<template>
  <view v-if="!table" class="tree-node" :class="{ 'tree-node--with-tree-line': treeLine }" :style="indentStyle" ref="el">
    <template v-if="treeLine">
      <view v-for="line in vLines" class="tree-line tree-vline" :style="line.style"></view>
      <view v-if="stat.level > 1" class="tree-line tree-hline" :style="hLineStyle"></view>
    </template>
    <view class="tree-node-inner">
      <slot :indentStyle="indentStyle"></slot>
    </view>
  </view>
  <tr v-else class="tree-node" ref="el">
    <slot :indentStyle="indentStyle"></slot>
  </tr>
</template>

<script lang="ts">
import { defineComponent, computed, watch } from "./vue"

let justToggleOpen = false
const afterToggleOpen = () => {
  justToggleOpen = true
  setTimeout(() => {
    justToggleOpen = false
  }, 100)
}

const cpt = defineComponent({
  // components: {},
  props: ["stat", "rtl", "btt", "indent", "table", "treeLine", "treeLineOffset", "processor"],
  emits: ["open", "close", "check"],
  setup(props, { emit }) {
    const indentStyle = computed(() => {
      return {
        [!props.rtl ? "paddingLeft" : "paddingRight"]:
          props.indent * (props.stat.level - 1) + "px",
      };
    });
    // watch checked
    watch(
      () => props.stat.checked,
      (checked) => {
        // fix issue: https://github.com/phphe/he-tree/issues/98
        // when open/close above node, the after nodes' states 'checked' and 'open' will be updated. It should be caused by Vue's key. We don't use Vue's key prop.
        if (justToggleOpen) {
          return
        }
        if (props.processor.afterOneCheckChanged(props.stat)) {
          emit("check", props.stat);
        }
      }
    );
    // watch open
    watch(
      () => props.stat.open,
      (open) => {
        if (justToggleOpen) {
          return
        }
        if (open) {
          emit("open", props.stat);
        } else {
          emit("close", props.stat);
        }
        afterToggleOpen()
      }
    );
    // tree lines
    const vLines = computed(() => {
      const lines: { style: object }[] = [];
      const hasNextVisibleNode = (stat) => {
        if (stat.parent) {
          let i = stat.parent?.children.indexOf(stat);
          do {
            i++
            let next = stat.parent.children[i]
            if (next) {
              if (!next.hidden) {
                return true
              }
            } else {
              break
            }
          } while (true);
        }
        return false
      }
      const leftOrRight = props.rtl ? 'right' : 'left'
      const bottomOrTop = props.btt ? 'top' : 'bottom'
      let current = props.stat
      while (current) {
        let left = (current.level - 2) * props.indent + props.treeLineOffset
        const hasNext = hasNextVisibleNode(current)
        const addLine = () => {
          lines.push({
            style: {
              [leftOrRight]: left + 'px',
              [bottomOrTop]: hasNext ? 0 : '50%',
            }
          })
        }
        if (current === props.stat) {
          if (current.level > 1) {
            addLine()
          }
        } else if (hasNext) {
          addLine()
        }
        current = current.parent
      }
      return lines
    })
    const hLineStyle = computed(() => {
      let left = (props.stat.level - 2) * props.indent + props.treeLineOffset
      const leftOrRight = props.rtl ? 'right' : 'left'
      return {
        [leftOrRight]: left + 'px',
      }
    })
    return { indentStyle, vLines, hLineStyle, }
  },
  // data() {
  //   return {}
  // },
  // computed: {},
  // watch: {},
  // methods: {},
  // created() {},
  // mounted() {}
});
export default cpt;
export type TreeNodeType = InstanceType<typeof cpt>;
</script>

<style>
/* tree line start */
.tree-node--with-tree-line {
  position: relative;
}

.tree-line {
  position: absolute;
  background-color: #bbbbbb;
}

.tree-vline {
  width: 1px;
  top: 0;
  bottom: 0;
}

.tree-hline {
  height: 1px;
  top: 50%;
  width: 10px;
}

/* tree line end */
</style>