<template>
    <el-input v-model="keyword" placeholder="请输入知识点名称" clearable prefix-icon="Search" style="margin-bottom: 20px"/>
    <el-tree ref="treeRef" v-if="knowledges.length" :data="knowledges" :props="{ label: 'name', children: 'children' }"
             :expand-on-click-node="false" :filter-node-method="filterNode" node-key="id" highlight-current
             default-expand-all :show-checkbox="allowMultiple" @node-click="handleNodeClick" @check="handleNodeCheck">
        <template #default="{ node, data }">
            <span>{{ data.name }}({{ data.id }})</span>
        </template>
    </el-tree>
</template>

<script setup name="KnowledgeTree">
import { ref, watch } from 'vue'
import {useInjectPaperKnowledgeCondition} from "@/views/dz/papers/hooks/usePaperKnowledgeCondition.js";

const props = defineProps({
    allowMultiple: Boolean
})

const treeRef = ref(null)
const keyword = ref('')
const {knowledges, knowledgeNode, knowledgeCheckNodes, onKnowledgeRemove} = useInjectPaperKnowledgeCondition()
const filterNode = function (value, data) {
    if (!value) return true
    // 支持按名称或ID搜索
    return data.name.indexOf(value) !== -1 || String(data.id).indexOf(value) !== -1
}

const handleNodeClick = function (data) {
    knowledgeNode.value = data
}

const handleNodeCheck = function (data, {checkedNodes}) {
    // 多选时，只保留叶子节点
    const newCheckedLeafNodes = checkedNodes.filter(k => !!!k.children?.length)
    
    // 获取当前已选知识点的ID集合
    const existingIds = new Set(knowledgeCheckNodes.value.map(k => k.id))
    
    // 获取新树中被选中的节点ID集合
    const newCheckedIds = new Set(newCheckedLeafNodes.map(k => k.id))
    
    // 找出新增的节点（在新选中但不在已选中）
    const addedNodes = newCheckedLeafNodes.filter(k => !existingIds.has(k.id))
    
    // 找出需要保留的旧节点（在新树中仍然存在的节点，或者不在新树中但用户没有取消选择）
    // 由于 el-tree 的 checkedNodes 只包含当前树中的节点，我们需要保留那些不在新树中的旧节点
    // 但移除那些在新树中被取消选择的节点
    const currentTreeIds = new Set(knowledges.value.flatMap(k => getAllNodeIds(k)))
    const removedFromTree = knowledgeCheckNodes.value.filter(k => !currentTreeIds.has(k.id))
    
    // 合并：保留不在当前树中的旧节点（跨科目的节点）+ 新选中的节点
    // 但需要移除在当前树中被取消选择的节点
    const keptOldNodes = knowledgeCheckNodes.value.filter(k => {
        // 如果节点不在当前树中，保留它（跨科目节点）
        if (!currentTreeIds.has(k.id)) {
            return true
        }
        // 如果节点在当前树中，且在新选中，保留它
        return newCheckedIds.has(k.id)
    })
    
    // 合并保留的旧节点和新添加的节点
    knowledgeCheckNodes.value = [...keptOldNodes, ...addedNodes]
}

// 辅助函数：获取树中所有节点的ID（包括子节点）
function getAllNodeIds(node) {
    const ids = [node.id]
    if (node.children && node.children.length > 0) {
        node.children.forEach(child => {
            ids.push(...getAllNodeIds(child))
        })
    }
    return ids
}

watch(keyword, val => {
    treeRef.value.filter(val)
})
onKnowledgeRemove((k) => {
    treeRef.value.setChecked(k, false, false)
})
</script>

<style scoped>

</style>