import { defineComponent, computed, ref, createVNode } from 'vue';
import { isUndefined, isFunction } from 'lodash-es';
import { useElementHover } from '@vueuse/core';
import getPrefixCls from '../_util/getPrefixCls';
import CaretDownOutlined from '../icon/CaretDownOutlined';
import LoadingOutlined from '../icon/LoadingOutlined';
import Checkbox from '../checkbox';
import FEllipsis from '../ellipsis';
import TextHightlight from '../text-highlight';
import { COMPONENT_NAME, INDENT } from './const';
import useTreeNode from './useTreeNode';

const prefixCls = getPrefixCls('tree-node');
const treeNodeProps = {
  value: {
    type: [String, Number],
    required: true
  },
  label: {
    type: [String, Function],
    required: true
  },
  disabled: {
    type: Boolean
  },
  selectable: {
    type: Boolean
  },
  checkable: {
    type: Boolean
  },
  isLeaf: {
    type: Boolean,
    default: false
  },
  level: {
    type: Number,
    default: 0
  },
  draggable: {
    type: Boolean,
    default: false
  },
  noExpand: {
    type: Boolean,
    default: false
  }
};
var treeNode = defineComponent({
  name: COMPONENT_NAME.TREE_NODE,
  props: treeNodeProps,
  setup(props, _ref) {
    let {
      slots
    } = _ref;
    const {
      root,
      isExpanded,
      isSelected,
      isChecked,
      isIndeterminate,
      isInline,
      isFirst
    } = useTreeNode(props);
    const disabled = computed(() => props.disabled);
    const selectable = computed(() => isUndefined(props.selectable) ? root.props.selectable : props.selectable);
    const checkable = computed(() => isUndefined(props.checkable) ? root.props.checkable : props.checkable);
    const classList = computed(() => {
      var _root$dragHighlightNo;
      return [prefixCls, disabled.value && 'is-disabled', isSelected.value && 'is-selected', isInline.value && 'is-inline', isFirst.value && 'is-inline-first', ((_root$dragHighlightNo = root.dragHighlightNode.value) === null || _root$dragHighlightNo === void 0 ? void 0 : _root$dragHighlightNo.value) === props.value && 'is-highlight'].filter(Boolean);
    });
    const style = computed(() => {
      if (isInline.value && !isFirst.value) {
        return {};
      }
      return {
        paddingLeft: `${(props.level - 1) * INDENT}px`
      };
    });
    let isLoaded = false;
    const isLoading = ref(false);
    const handleClickSwitcher = async event => {
      const node = root.nodeList.get(props.value);
      if (!isLoaded && root.props.loadData && (!node.children || node.children.length === 0)) {
        isLoading.value = true;
        try {
          await root.props.loadData(node.origin);
          isLoaded = true;
          root.expandNode(props.value, event);
        } catch (e) {
          console.error(e);
        }
        isLoading.value = false;
      } else {
        root.expandNode(props.value, event);
      }
    };
    const handleClickContent = event => {
      if (disabled.value) {
        return;
      }
      // 默认 select 行为
      if (selectable.value) {
        return root.selectNode(props.value, event);
      }
      // 再 check 行为
      if (checkable.value) {
        return root.checkNode(props.value, event);
      }
      // 再展开行为
      if (!props.isLeaf) {
        handleClickSwitcher(event);
      }
    };
    const handleClickCheckbox = event => {
      if (disabled.value) {
        return;
      }
      if (checkable.value) {
        return root.checkNode(props.value, event);
      }
    };
    const handleStopClickPrefix = event => {
      event.stopPropagation();
    };
    const renderDragTag = () => {
      const dragOverInfo = root.dragOverInfo.value;
      if (!dragOverInfo) {
        return;
      }
      if (dragOverInfo.position === 'inside') {
        return;
      }
      if ((dragOverInfo === null || dragOverInfo === void 0 ? void 0 : dragOverInfo.node.value) === props.value) {
        const style = {};
        style.left = `${props.level * INDENT + 9}px`;
        return createVNode("div", {
          "class": [`${prefixCls}-drag-over`, `is-${dragOverInfo === null || dragOverInfo === void 0 ? void 0 : dragOverInfo.position}`],
          "style": style
        }, null);
      }
      return null;
    };
    const renderSwitcher = () => {
      if (props.isLeaf) {
        const leafClass = [`${prefixCls}-switcher`];
        if (props.noExpand) {
          leafClass.push('no-expand');
        }
        return createVNode("span", {
          "class": leafClass
        }, null);
      }
      const icon = isLoading.value ? createVNode(LoadingOutlined, null, null) : createVNode(CaretDownOutlined, {
        "class": [`${prefixCls}-switcher-icon`, isExpanded.value ? 'is-expanded' : '']
      }, null);
      return createVNode("span", {
        "class": `${prefixCls}-switcher`,
        "onClick": handleClickSwitcher
      }, [icon]);
    };
    const renderCheckbox = () => {
      if (!checkable.value) {
        return null;
      }
      return createVNode("span", {
        "class": `${prefixCls}-checkbox`
      }, [createVNode(Checkbox, {
        "indeterminate": isIndeterminate.value,
        "modelValue": isChecked.value,
        "onChange": handleClickCheckbox,
        "disabled": props.disabled
      }, null)]);
    };
    const treeNodeElement = ref();
    const isHovered = useElementHover(treeNodeElement);
    const slotParams = computed(() => {
      return {
        isHovered: isHovered.value,
        value: props.value
      };
    });
    const renderPrefix = () => {
      var _slots$prefix;
      if (!slots.prefix) {
        return null;
      }
      return createVNode("span", {
        "class": `${prefixCls}-content-prefix`,
        "onClick": handleStopClickPrefix
      }, [(_slots$prefix = slots.prefix) === null || _slots$prefix === void 0 ? void 0 : _slots$prefix.call(slots, slotParams.value)]);
    };
    const renderSuffix = () => {
      var _slots$suffix;
      if (!slots.suffix) {
        return null;
      }
      return createVNode("span", {
        "class": `${prefixCls}-content-suffix`,
        "onClick": handleStopClickPrefix
      }, [(_slots$suffix = slots.suffix) === null || _slots$suffix === void 0 ? void 0 : _slots$suffix.call(slots, slotParams.value)]);
    };
    const renderLabel = () => {
      const node = root.nodeList.get(props.value);
      if (isFunction(props.label)) {
        return createVNode("span", {
          "class": `${prefixCls}-content-label`
        }, [props.label(node)]);
      } else if (isFunction(root.slots.label)) {
        return createVNode("span", {
          "class": `${prefixCls}-content-label`
        }, [root.slots.label(node)]);
      }
      return createVNode(FEllipsis, {
        "class": `${prefixCls}-content-label`
      }, {
        default: () => [root.props.filterTextHighlight && root.props.filterText ? createVNode(TextHightlight, {
          "strict": true,
          "searchValues": [root.props.filterText]
        }, {
          default: () => [props.label]
        }) : props.label]
      });
    };
    return () => createVNode("div", {
      "ref": treeNodeElement,
      "class": classList.value,
      "style": style.value,
      "data-value": props.value,
      "draggable": props.draggable,
      "onDragstart": event => {
        root.handleDragstart(props.value, event);
      },
      "onDragenter": event => {
        root.handleDragenter(props.value, event);
      },
      "onDragover": event => {
        root.handleDragover(props.value, event);
      },
      "onDragleave": event => {
        root.handleDragleave(props.value, event);
      },
      "onDragend": event => {
        root.handleDragend(props.value, event);
      },
      "onDrop": event => {
        root.handleDrop(props.value, event);
      }
    }, [renderDragTag(), renderSwitcher(), renderCheckbox(), createVNode("span", {
      "class": `${prefixCls}-content`,
      "onClick": handleClickContent
    }, [renderPrefix(), renderLabel(), renderSuffix()])]);
  }
});

export { treeNode as default };
