<template>
    <el-card shadow="hover" :body-style="{padding:'12px'}">
        <div style="display: flex; align-items: center;">
            <el-icon style="color: blue;"><menu/></el-icon>
            <span style="font-weight: 600;">菜单</span>
            <el-tag type="primary" size="small" effect="plain" style="margin-left: 8px;">已选择：{{ selectedCount }}</el-tag>
        </div> 
        <el-divider style="margin: 10px 0;"/>
        <div style="display: flex;gap: 8px;margin-bottom: 8px; align-items: center;">
            <el-button size="small" :type="expandAll ? 'success' : 'default'" @click="toggleExpand">{{expandAll ? '折叠' :'展开'}}</el-button>
            <el-button size="small" :type="allSelect ? 'warning' : 'default'" @click="toggleAll">{{allSelect ? '取消选择' :'全选'}}</el-button>
            <el-checkbox v-model="parentLink">父子联动</el-checkbox>
            <el-input v-model="filterText" placeholder="输入关键字进行过滤" clearable style="max-width: 260px; margin-left: auto;">
            <template #prefix>
                <el-icon>
                    <search />
                </el-icon>
            </template>
            </el-input>
        </div>
        <el-tree ref="treeRef"
            :data="filterText ? filteredTreeData : treeData"
            node-key="id"
            show-checkbox
            :default-expand-all="expandAll"
            :check-strictly="!parentLink"
            :props="{label:'label',children:'children'}"
            :filter-node-method="filterNode"
            @check="updateSelectedCount"
            highlight-current
            v-loading="loading"
            element-loading-text="菜单加载中..."
            style="border: 1px solid black;border-radius: 6px;padding: 6px;height: 360px;overflow: auto;"/>
    </el-card>
</template>

<script setup lang="ts">
import { ref,watch,onMounted,nextTick } from "vue";
import { Menu,Search } from "@element-plus/icons-vue";
import { treeselect} from '@/api/system/menu/index';
import type { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
import { treeselectByDeptId } from "@/api/system/dept/index";
type TreeNode = MenuTreeOption;

const props = defineProps<{
    deptId?:number|string;
    initialMenuIds?: Array<number|string>; // 初始菜单ID列表
}>();
const emit = defineEmits<{
    (e: 'save', menuIds: Array<number|string>): void;// 定义save传递menuIds数组
}>();

const loading = ref(false);
const treeRef = ref();
const treeData = ref<TreeNode[]>([]);
const menuNodeMap = new Map<string, { node: any; parentId?: string }>();// 菜单节点缓存映射表
const filterMap = new Map<string, any>();
const filteredTreeData = ref<TreeNode[]>([]);// 过滤后的树数据
const checkedKeySet = new Set<string>(); // 全局选中集合
const expandAll = ref(false);// 展开
const allSelect = ref(false);// 全选
const parentLink = ref(true);// 父子联动
const filterText = ref('');// 搜索文本
const selectedCount = ref(0);

//id转换
const normalizeIds = (nodes: any[]) => {
    nodes?.forEach((n) => {
        n.id = String(n.id);
        if (n.parentId !== undefined && n.parentId !== null) {
            n.parentId = String(n.parentId);
        }
        if (n.children?.length) normalizeIds(n.children);
    });
};
//构建菜单节点缓存映射表
const rebuildMenuNodeCache = (nodes: any[]) => {
    menuNodeMap.clear();
    const traverse = (node: any, explicitParentId?: string) => {
        if (!node) return;
        const id = String(node.id);
        const parentId = explicitParentId ?? (node.parentId !== undefined && node.parentId !== null ? String(node.parentId) : undefined);
        menuNodeMap.set(id, { node, parentId });
        if (node.children && Array.isArray(node.children) && node.children.length > 0) {
            node.children.forEach((child: any) => traverse(child, id));
        }
    };
    if (Array.isArray(nodes)) {
        nodes.forEach((root) => traverse(root));
    }
};

//过滤输入框搜索
const filterNode = (value: string, data: any) => {
    if(!value){
        return true;
    }
    if(!data.label){
        return true;
    }
    const isMatch = data.label.toLowerCase().includes(value.toLowerCase());
    if(isMatch){
        filterMap.set(data.id, data);
        if(data.children && Array.isArray(data.children)&& data.children.length > 0){
            const collectChildren = (node: any) => {
                if(Array.isArray(node.children)){
                    node.children.forEach((child: any) => {
                        filterMap.set(child.id, child);
                        collectChildren(child);
                    });
                }   
            }
            collectChildren(data);
        }
    }
    return isMatch;
}
// 恢复树结构
const extractFilteredTree = (): TreeNode[] => {
    if (filterMap.size === 0) {
        return treeData.value;
    }
    const nodesToShow = new Set<string>();// 存储显示节点Id
    const matchedNodeIds = Array.from(filterMap.keys());
    
    matchedNodeIds.forEach(id => {
        nodesToShow.add(id);
    });
    // 获取所有父节点
    matchedNodeIds.forEach(nodeId => {
        let current = menuNodeMap.get(nodeId);
        while (current && current.parentId) {
            nodesToShow.add(current.parentId);
            current = menuNodeMap.get(current.parentId);
        }
    });
    // 提取这些节点，恢复树结构
    const extractNodes = (nodes: TreeNode[]): TreeNode[] => {
        const result: TreeNode[] = [];
        nodes.forEach(node => {
            const nodeId = String(node.id);
            if (nodesToShow.has(nodeId)) {
                const newNode: TreeNode = {
                    ...node,// 复制节点所有属性
                    children: node.children && Array.isArray(node.children) 
                        ? extractNodes(node.children) 
                        : []
                };
                result.push(newNode);
            }
        });
        return result;
    };
    return extractNodes(treeData.value);
}
//获取当前显示所有按钮Id（包括勾选和不勾选的）
const collectSelectableNodeIds = (nodes: TreeNode[] = []): string[] => {
    const ids: string[] = [];
    const traverse = (node: TreeNode) => {
        if (!node) {
            return;
        }
        const id = String(node.id);
        const menuType = (node as any).menuType;
        if (!parentLink.value || menuType !== 'M') {
            ids.push(id);
        }
        if (node.children && Array.isArray(node.children)) {
            node.children.forEach(traverse);
        }
    };
    nodes.forEach(traverse);
    return ids;
};

// 更新全选按钮状态
const updateAllSelectState = () => {
    const currentData = filterText.value ? filteredTreeData.value : treeData.value;
    if (currentData.length === 0) {
        allSelect.value = false;
        return;
    }
    const targetIds = collectSelectableNodeIds(currentData);
    if (targetIds.length === 0) {
        allSelect.value = false;
        return;
    }
    allSelect.value = targetIds.every(id => checkedKeySet.has(id));
};

//选中数量
const updateSelectedCount = () => {
    if (!treeRef.value) {
        selectedCount.value = 0;
        checkedKeySet.clear();
        allSelect.value = false;
        return;
    }
    const currentVisibleChecked = getAllCheckedKeys().map(key => String(key));
    let effectiveKeys: string[] = [];

    if (filterText.value) {
        const visibleIds = collectSelectableNodeIds(filteredTreeData.value);
        visibleIds.forEach(id => checkedKeySet.delete(id));
        currentVisibleChecked.forEach(id => checkedKeySet.add(id));
        effectiveKeys = Array.from(checkedKeySet);
    } else {
        checkedKeySet.clear();
        currentVisibleChecked.forEach(id => checkedKeySet.add(id));
        effectiveKeys = Array.from(checkedKeySet);
    }

    const totalKeys = new Set<string>(effectiveKeys);

    effectiveKeys.forEach(key => {
        let current = menuNodeMap.get(key);
        while (current && current.parentId) {
            if (!totalKeys.has(current.parentId)) {
                totalKeys.add(current.parentId);
            }
            current = menuNodeMap.get(current.parentId);
        }
    });

    selectedCount.value = totalKeys.size - 1;
    if(selectedCount.value < 0){
        selectedCount.value = 0;
    }
    updateAllSelectState();  
    emit('save', effectiveKeys);
};

//展开、折叠按钮
const toggleExpand = () => {
    expandAll.value = !expandAll.value;
    expandTreeNodes(treeData.value,expandAll.value);
};

const expandTreeNodes = (nodes: any[], expand: boolean) => {
    nodes?.forEach((n:any) =>{
        const m = treeRef.value?.store?.nodesMap;
        if (m?.[n.id]){
            m[n.id].expanded = expand;
        }
        if (n.children?.length){
            expandTreeNodes(n.children, expand);
        }
    });
}

//点击全选、取消全选按钮
const toggleAll = () => {
    if (!treeRef.value) return;
    const currentData = filterText.value ? filteredTreeData.value : treeData.value;
    const targetIds = collectSelectableNodeIds(currentData);
    if (targetIds.length === 0) {
        allSelect.value = false;
        return;
    }

    const shouldSelectAll = !targetIds.every(id => checkedKeySet.has(id));
    if (shouldSelectAll) {
        targetIds.forEach(id => checkedKeySet.add(id));
    } else {
        targetIds.forEach(id => checkedKeySet.delete(id));
    }

    treeRef.value.setCheckedKeys(Array.from(checkedKeySet));
    updateSelectedCount();
};

//获取所有选中的keys
const getAllCheckedKeys = () => {
    if (!treeRef.value) return [];
    let checkedKeys = treeRef.value.getCheckedKeys() || [];
    if (!parentLink.value) {
        const halfCheckedKeys = treeRef.value.getHalfCheckedKeys() || [];
        if (halfCheckedKeys && halfCheckedKeys.length) {
            checkedKeys = [...checkedKeys, ...halfCheckedKeys];
        }
    }
    if (parentLink.value) {
        const store = treeRef.value.store;
        if (store && store.nodesMap) {
            checkedKeys = checkedKeys.filter(key => {
                const node = store.nodesMap[String(key)];
                if (!node) {
                    return true;
                }
                const data = node.data || {};
                const menuType = data.menuType;
                if (menuType === 'M') {
                    return false;
                }
                return true;
            });
        }
    }
    return checkedKeys;
};

//加载完整菜单树
const loadAllTree = async () => {
    loading.value = true;
    const res = await treeselect();
    const data = res.data || [];
    normalizeIds(data);
    treeData.value = data;
    rebuildMenuNodeCache(treeData.value);
    await nextTick();
    loading.value = false;
};
//获取树结构
const resolveMenuTree = (payload: any): any[] => {
    if (Array.isArray(payload)) {
        return payload;
    }
    if (payload && typeof payload === 'object') {
        if (Array.isArray(payload.menus)) {
            return payload.menus;
        }
        if (Array.isArray(payload.data)) {
            return payload.data;
        }
    }
    return [];
};
//提取节点Id
const extractMenuIds = (nodes: any[] = []): string[] => {
    const ids: string[] = [];
    const traverse = (node: any) => {
        if (!node) return;
        const candidate = [node.id, node.value, node.menuId, node.key].find(value => value !== undefined && value !== null);
        if (candidate !== undefined) {
            const id = String(candidate);
            if (!ids.includes(id)) {
                ids.push(id);
            }
        }
        if (node.children && Array.isArray(node.children)) {
            node.children.forEach(traverse);
        }
    };
    nodes.forEach(traverse);
    return ids;
};
//设置对应节点为选中
const applyKeysToTree = (keys: string[]) => {
    if (!treeRef.value) {
        return;
    }
    const store = treeRef.value.store;
    if (!store || !store.nodesMap) {
        nextTick(() => {
            applyKeysToTree(keys);
        });
        return;
    }
    const normalized = keys.filter(key => store.nodesMap[String(key)]);
    if (normalized.length > 0) {
        treeRef.value.setCheckedKeys(normalized);
        updateSelectedCount();
    } else {
        updateSelectedCount();
    }
};

//部门关联菜单
const applyCheckedFromDept = async (deptId: number | string) => {
    if (!deptId) {
        if (treeRef.value) {
            treeRef.value.setCheckedKeys([]);
            updateSelectedCount();
        }
        return;
    }
    try {
        const res = await treeselectByDeptId(deptId) as any;
        const menuTree = resolveMenuTree(res);
        const checkedKeys = extractMenuIds(menuTree);

        const fallbackKeys = props.initialMenuIds?.length ? props.initialMenuIds.map(id => String(id)) : [];
        const finalCheckedKeys = checkedKeys.length ? checkedKeys : fallbackKeys;

        if (finalCheckedKeys.length === 0) {
            if (treeRef.value) {
                treeRef.value.setCheckedKeys([]);
                updateSelectedCount();
            }
            return;
        }
        await nextTick();
        applyKeysToTree(finalCheckedKeys);
    } catch (error) {
        if (treeRef.value) {
            treeRef.value.setCheckedKeys([]);
            updateSelectedCount();
        }
    }
};

onMounted(async () => {
    await loadAllTree();
    if (props.deptId) {
        await applyCheckedFromDept(props.deptId);
    }
});

watch(() => filterText.value, (v) => {
    filterMap.clear();
    if (v) {
        treeRef.value?.filter(v);
        nextTick(() => {
            filteredTreeData.value = extractFilteredTree();
            nextTick(() => {
                expandTreeNodes(filteredTreeData.value, true);
                applyKeysToTree(Array.from(checkedKeySet));
            });
        });
    } else {
        filteredTreeData.value = [];
        nextTick(() => {
            applyKeysToTree(Array.from(checkedKeySet));
        });
    }
});

watch(() => props.deptId, async(n) => {
    if (n) {
        await applyCheckedFromDept(n);
    } else {
        if (treeRef.value) {
            treeRef.value.setCheckedKeys([]);
            updateSelectedCount();
        }
        await loadAllTree();
    }
});

watch(() => props.initialMenuIds, async(menuIds) => {
    if (menuIds && menuIds.length > 0 && treeRef.value && treeData.value.length > 0) {
        await nextTick();
        applyKeysToTree(menuIds.map(id => String(id)));
    }
}, { immediate: false });

defineExpose({ getAllCheckedKeys });
</script>
