<template>
    <div class="data-permission-tree">
        <tree-node v-for="node in treeData" :key="node.id" :node="node" :selected-keys="computedSelectedKeys"
            :indeterminate-keys="indeterminateKeys" :disabled-keys="disabledKeys" :expanded-keys="expandedKeys"
            @check="handleCheck" @expand="handleExpand" />
    </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import TreeNode from './TreeNode.vue'
import type { TreeData, CheckedKeys } from './types'

interface Props {
    data?: TreeData[]
    selectedKeys?: number[]
    disabled?: boolean
}

interface Emits {
    (e: 'update:selectedKeys', keys: number[]): void
    (e: 'check', keys: CheckedKeys): void
}

const props = withDefaults(defineProps<Props>(), {
    data: () => [],
    selectedKeys: () => [],
    disabled: false
})

const emit = defineEmits<Emits>()

// 内部选中键值
const innerSelectedKeys = ref<number[]>([])
const expandedKeys = ref<Set<number>>(new Set())
const indeterminateKeys = ref<Set<number>>(new Set())

// 视觉上的级联选中键值（用于显示效果，不影响实际值）
const visualSelectedKeys = ref<Set<number>>(new Set())

// 计算禁用的键值
const disabledKeys = computed(() => {
    const keys = new Set<number>()
    if (props.disabled) {
        const collectKeys = (nodes: TreeData[]) => {
            nodes.forEach(node => {
                keys.add(node.id)
                if (node.children && node.children.length > 0) {
                    collectKeys(node.children)
                }
            })
        }
        collectKeys(props.data)
    }
    return keys
})

// 初始化选中状态
onMounted(() => {
    innerSelectedKeys.value = [...props.selectedKeys]
    updateIndeterminateState()

    // 默认展开所有节点
    const expandAll = (nodes: TreeData[]) => {
        nodes.forEach(node => {
            expandedKeys.value.add(node.id)
            if (node.children && node.children.length > 0) {
                expandAll(node.children)
            }
        })
    }
    expandAll(props.data)
})

// 监听外部选中状态变化
watch(() => props.selectedKeys, (newVal) => {
    innerSelectedKeys.value = [...newVal]
    updateIndeterminateState()
})

// 更新半选状态
const updateIndeterminateState = () => {
    const newIndeterminateKeys = new Set<number>()

    const traverse = (nodes: TreeData[]) => {
        nodes.forEach(node => {
            if (node.children && node.children.length > 0) {
                // 递归处理子节点
                traverse(node.children)

                // 检查当前节点是否为半选状态
                const childCheckedCount = node.children.filter(child =>
                    innerSelectedKeys.value.includes(child.id)
                ).length

                const childIndeterminateCount = node.children.filter(child =>
                    newIndeterminateKeys.has(child.id)
                ).length

                // 如果有子节点被选中或半选，则父节点为半选状态
                if (childCheckedCount > 0 || childIndeterminateCount > 0) {
                    newIndeterminateKeys.add(node.id)
                }
            }
        })
    }

    traverse(props.data)
    indeterminateKeys.value = newIndeterminateKeys
}

// 获取节点的所有后代节点ID
const getAllDescendantIds = (node: TreeData): number[] => {
    const ids: number[] = []

    const traverse = (children: TreeData[] | undefined) => {
        if (children && children.length > 0) {
            children.forEach(child => {
                ids.push(child.id)
                traverse(child.children)
            })
        }
    }

    traverse(node.children)
    return ids
}

// 查找指定ID节点的路径（包含该节点本身）
const findNodePath = (nodes: TreeData[], targetId: number): TreeData[] | null => {
    for (const node of nodes) {
        if (node.id === targetId) {
            return [node]
        }

        if (node.children && node.children.length > 0) {
            const childPath = findNodePath(node.children, targetId)
            if (childPath) {
                return [node, ...childPath]
            }
        }
    }
    return null
}

// 处理节点选中
const handleCheck = (node: TreeData, checked: boolean) => {
    if (props.disabled || disabledKeys.value.has(node.id)) {
        return
    }

    let newSelectedKeys = [...innerSelectedKeys.value]
    const keyIndex = newSelectedKeys.indexOf(node.id)

    if (checked) {
        // 选中节点：只添加当前节点
        if (keyIndex === -1) {
            newSelectedKeys.push(node.id)
        }

        // 获取所有后代节点ID并从选中列表中移除
        const descendantIds = getAllDescendantIds(node)
        newSelectedKeys = newSelectedKeys.filter(id => !descendantIds.includes(id))

        // 获取所有祖先节点ID并从选中列表中移除
        const path = findNodePath(props.data, node.id)
        if (path) {
            // 排除当前节点本身，只获取祖先节点
            const ancestorIds = path.slice(0, -1).map(ancestor => ancestor.id)
            newSelectedKeys = newSelectedKeys.filter(id => !ancestorIds.includes(id))
        }
    } else {
        // 取消选中节点
        if (keyIndex !== -1) {
            newSelectedKeys.splice(keyIndex, 1)
        }
    }

    innerSelectedKeys.value = newSelectedKeys
    updateIndeterminateState()

    // 触发事件
    emit('update:selectedKeys', newSelectedKeys)
    emit('check', {
        checked: newSelectedKeys,
        indeterminate: Array.from(indeterminateKeys.value)
    })
}

// 处理展开/折叠
const handleExpand = (nodeId: number) => {
    const newExpandedKeys = new Set(expandedKeys.value)
    if (newExpandedKeys.has(nodeId)) {
        newExpandedKeys.delete(nodeId)
    } else {
        newExpandedKeys.add(nodeId)
    }
    expandedKeys.value = newExpandedKeys
}

// 计算最终的树数据
const treeData = computed(() => props.data)

// 计算选中键值
const selectedKeys = computed(() => innerSelectedKeys.value)

// 计算用于显示的选中键值（包括级联效果）
const computedSelectedKeys = computed(() => {
    // 合并实际选中的键值和视觉上级联选中的键值
    const allSelectedKeys = new Set(innerSelectedKeys.value)

    // 对于每个选中的节点，将其所有子节点也添加到视觉选中集合中
    const addDescendants = (nodes: TreeData[], parentSelected: boolean) => {
        nodes.forEach(node => {
            // 如果父节点被选中或者当前节点本身被选中
            const isSelected = parentSelected || innerSelectedKeys.value.includes(node.id)

            // 如果应该显示为选中状态，则添加到集合中
            if (isSelected) {
                allSelectedKeys.add(node.id)
            }

            // 递归处理子节点
            if (node.children && node.children.length > 0) {
                addDescendants(node.children, isSelected)
            }
        })
    }

    addDescendants(props.data, false)
    return Array.from(allSelectedKeys)
})
</script>

<style scoped>
.data-permission-tree {
    width: 100%;
}
</style>