<template>
    <div class="ps-tree-node component" :class="[{ draging: status === ENiuTreeStatus.DragIng }]">
        <div class="ps-tree-node-wrapper" ref="nodeEL" :draggable="draggable" :onDragstart="onDragstart"
            :onDragend="onDragend" :onDrop="onDrop" :onDragover="onDragover" :onDragleave="onDragleave"
            @click.stop="emit('click', data)">
            <slot :data="data" :deep="level" :dataSourceKey="dataSourceKey" :status="status">
                <div :style="{
                    marginLeft: level * 10 + 'px',
                    'position': 'relative',
                    zIndex: 10
                }">
                    {{ data.title }} - {{ level * 10 + 'px' }}
                </div>
            </slot>
            <div :style="{ marginLeft: level * 10 + 'px' }" :class="[
                {
                    'ps-tree-drag-up':
                        dataSourceKey != data.key &&
                        dataSourceKey != undefined &&
                        !isChildOf(data.key, dataSourceKey, list) &&
                        status === ENiuTreeStatus.DragUp,
                    'ps-tree-drag-in':
                        dataSourceKey != data.key &&
                        dataSourceKey &&
                        !isChildOf(data.key, dataSourceKey, list) &&
                        status === ENiuTreeStatus.DragIn,
                    'ps-tree-drag-down':
                        dataSourceKey != data.key &&
                        dataSourceKey &&
                        !isChildOf(data.key, dataSourceKey, list) &&
                        status === ENiuTreeStatus.DragDown,
                },
            ]"></div>
        </div>
        <div class="ps-tree-sub-node" v-if="(opts.justOpen || data.isExpand) && data.children && data.children.length">
            <template v-for="(item, index) in sortedList" :key="item.key">
                <node
                    @onDragstart="(e: INiuTreeKey)=>emit('onDragstart', e)"
                    @onDragend="(e: INiuTreeKey)=>emit('onDragend', e)"
                    @onDrop="(e: INiuTreeKey, s?: ENiuTreeStatus)=>emit('onDrop', e, s)"
                    @onDragover="(e: INiuTreeKey)=>emit('onDragover', e)"
                    @onDragleave="(e: INiuTreeKey)=>emit('onDragleave', e)"
                    @expand="(e: INiuTreeData)=>emit('expand', e)"
                    @click="(e: INiuTreeData)=>emit('click', e)"
                    :data-source-key="dataSourceKey"
                    :data="item"
                    :list="list"
                    :level="level + 1"
                >
                    <!-- <template #default="{data, deep, dataSourceKey, status}: {data: INiuTreeData, deep: number, dataSourceKey:INiuTreeKey, status:ENiuTreeStatus}"> -->
                    <template #default="fuck">
                        <aa v-bind="fuck"></aa>
                        <!-- <renderNode :data="fuck" :slots="$slots"></renderNode> -->
                        <!-- <slot :data="data" :deep="deep" :dataSourceKey="dataSourceKey" :status="status"></slot> -->
                    </template>
                </node>
            </template>
        </div>
    </div>
</template>

<script lang="ts" setup>
import node from './node.vue'
import { inject, ref, provide, renderSlot, useSlots, watch, readonly, computed } from 'vue'
import { isChildOf } from './util'
import renderNode from './renderNode'
import type { INiuTreeData, INiuTreeKey  } from './type'
import { ENiuTreeStatus } from './type';
import {betterDirectorySort} from "./better-directory-sort"

const sortedList = computed(()=>{
    if(opts.sort){
        return props.data.children.sort((a, b) => {
            return betterDirectorySort(
                { name: a.title, isDirectory: a.isFolder },
                { name: b.title, isDirectory: b.isFolder },
            );
        });
    }
    return props.data.children
})


const props = withDefaults(
    defineProps<{
        data: INiuTreeData
        list: INiuTreeData[]
        dataSourceKey?: INiuTreeKey
        level?: number
    }>(),
    {
        level: 0,
    }
)
const slots = useSlots()
const aa = (fuck: any)=>renderSlot(slots, "default", fuck)

watch(()=>props.data.isExpand, ()=>{
    emit("expand", props.data)
})

const opts = inject("tree:opts", {
    justOpen: false,
    sort: false,
})
const emit = defineEmits<{
    (e: 'click', data: INiuTreeData): void
    (e: 'expand', data: INiuTreeData): void
    (e: 'onDragstart', key: INiuTreeKey): void
    (e: 'onDragend', key: INiuTreeKey): void
    (e: 'onDrop', key: INiuTreeKey, status?: ENiuTreeStatus): void
    (e: 'onDragover', key: INiuTreeKey): void
    (e: 'onDragleave', key: INiuTreeKey): void
}>()
const draggable = opts.sort?readonly(ref(false)):ref(true)
const status = ref<ENiuTreeStatus>()
const nodeEL = ref<HTMLDivElement>()
provide("draggable", draggable)
function onDragstart(event: DragEvent) {
    // 开始拖拽
    if (event.dataTransfer) {
        event.dataTransfer.dropEffect = 'move'
        event.dataTransfer.effectAllowed = 'move'
        if (nodeEL.value) {
            let clone = nodeEL.value.cloneNode(true) as HTMLDivElement
            clone.id = 'dragging_node'
            clone.style.display = 'inline-block'
            clone.style.position = 'absolute'
            clone.style.zIndex = '100000'
            clone.style.width = '100px'
            clone.style.top = '-100000px'
            document.body.append(clone)
            event.dataTransfer.setDragImage(clone, -4, -4)
        }
        emit('onDragstart', props.data.key)
        status.value = ENiuTreeStatus.DragIng
    }
}
function onDragend() {
    // 结束拖拽
    let clone = document.getElementById('dragging_node')
    clone?.remove()
    status.value = undefined
    emit('onDragend', props.data.key)
}
function onDrop(e: DragEvent) {
    e.preventDefault()
    emit('onDrop', props.data.key, status.value)
    status.value = undefined
}

function onDragover(event: DragEvent) {
    event.preventDefault()
    if (!props.dataSourceKey) return
    if (props.dataSourceKey === props.data.key) return
    if (
        props.dataSourceKey &&
        isChildOf(props.data.key, props.dataSourceKey, props.list)
    )
        return
    const y = event.offsetY
    const h = (event.currentTarget as HTMLDivElement).offsetHeight
    if (y < h / 3) {
        status.value = ENiuTreeStatus.DragUp
    } else if (y <= (h * 2) / 3 && y >= h / 3 && props.data.children) {
        status.value = ENiuTreeStatus.DragIn
    } else if (y > (h * 2) / 3) {
        status.value = ENiuTreeStatus.DragDown
    } else {
        status.value = undefined
    }
    emit('onDragover', props.data.key)
}
function onDragleave() {
    if (!props.dataSourceKey) return
    if (props.dataSourceKey === props.data.key) return
    if (
        props.dataSourceKey &&
        isChildOf(props.data.key, props.dataSourceKey, props.list)
    )
        return

    // 拖拽离开元素上
    status.value = undefined
    emit('onDragleave', props.data.key)
}
</script>