import { isEmpty } from '@/utils/validate';

/**
 * 获取指定节点的父节点和爷节点的 key
 * @param {Array} treeData - 树形数据数组，每个节点可以包含 children 属性表示子节点
 * @param {string|number} key - 要查找的目标节点的 key 值
 * @param {Object} fieldNames - 节点中表示 key 的字段名配置，默认为 { key: 'key' }
 * @returns {Array} - 包含父节点和爷节点 key 的数组
 */
export function getAnsKeys(treeData, key, fieldNames = { key: 'key' }) {
    const parentKeys = [];
    // 递归查找目标节点并记录其父节点信息
    const findNode = (currentNodes, parentKey = null, grandParentKey = null) => {
        for (const node of currentNodes) {
            if (node[fieldNames.key] === key) {
                // 如果存在父节点，添加到结果数组
                if (parentKey) {
                    parentKeys.push(parentKey);
                }
                // 如果存在爷节点，添加到结果数组
                if (grandParentKey) {
                    parentKeys.push(grandParentKey);
                }
                return;
            }
            if (node.children) {
                // 递归调用，更新父节点和爷节点信息
                findNode(node.children, node[fieldNames.key], parentKey);
            }
        }
    };
    findNode(treeData);
    return parentKeys;
}


/**
 * 获取指定节点的子节点和孙节点的 key
 * @param {Array} treeData - 树形结构数据，每个节点包含 id、children 等属性
 * @param {Array} keys - 要选中的节点 ID 数组
 * @returns {Array} - 最终选中的节点 ID 数组
 */
export function getDscKeys(treeData, keys) {
    // 初始化所有节点的选中状态为 false
    function initSelection(tree) {
        tree.forEach((node) => {
            node.selected = false;
            if (node.children) {
                initSelection(node.children);
            }
        });
    }

    // 选中父节点时，递归选中其所有子节点
    function selectParent(node) {
        node.selected = true;
        if (node.children) {
            node.children.forEach((child) => {
                selectParent(child);
            });
        }
    }

    // 选中子节点时，更新父节点的选中状态
    function selectChild(node) {
        node.selected = true;
        let parent = node.parent;
        while (parent) {
            const allChildrenSelected = parent.children.every((child) => child.selected);
            parent.selected = allChildrenSelected;
            parent = parent.parent;
        }
    }

    // 为所有节点设置 parent 属性
    function setParent(tree, parent = null) {
        tree.forEach((node) => {
            node.parent = parent;
            if (node.children) {
                setParent(node.children, node);
            }
        });
    }

    // 根据传入的 key 选中节点
    function selectNodes(tree, keys) {
        tree.forEach((node) => {
            if (keys.includes(String(node.id))) {
                selectParent(node);
                selectChild(node);
            }
            if (node.children) {
                selectNodes(node.children, keys);
            }
        });
    }

    // 收集所有选中节点的 id
    function collectSelectedIds(tree) {
        const selectedIds = [];
        const stack = [...tree];
        while (stack.length > 0) {
            const node = stack.pop();
            if (node.selected) {
                selectedIds.push(node.id);
            }
            if (node.children) {
                stack.push(...node.children);
            }
        }
        return selectedIds;
    }

    // 初始化选中状态
    initSelection(treeData);
    // 设置 parent 属性
    setParent(treeData);
    // 处理节点选中逻辑
    selectNodes(treeData, keys);
    // 收集选中节点的 id
    return collectSelectedIds(treeData);
}


export function getWithoutDscKeys (treeData, keys, fieldNames = { key: 'id' }) {
    let withoutDesKeys = [];
    let withoutDesNodes = [];
    const allNodes = getAllNodes(treeData);
    if (keys.length === 1) {
        // 只选中一个节点
        const node = allNodes.find(n => n.id === keys[0]);
        withoutDesKeys.push(node[fieldNames.key]);
        withoutDesNodes.push(node);
    } else {
        // 选中多个节点
        for (let i = 0; i < keys.length; i++) {
            // 找到当前节点
            const node = allNodes.find(n => n.id === keys[i]);
            if (!keys.includes(node.pid)) {
                // 选择的节点对应的父节点没有被选择， 则添加到结果中
                withoutDesKeys.push(node[fieldNames.key]);
                withoutDesNodes.push(node);
            }
        }
    }
    // 返回包含三个数组的对象
    return {
        withoutDesKeys,
        withoutDesNodes
    };
}



/**
 * 
 * @param {Array} treeData 
 * @param {String} targetId 
 * @param {Array} checkedKeys 
 * @returns 
 */
export function delAnsAndDscKeys(treeData, targetId, checkedKeys) {
    // 存储需要移除的节点 ID
    let keysToRemove = [];

    // 递归收集要删除的节点及其所有子节点的 ID
    function collectKeysToRemove(node) {
        keysToRemove.push(node.id);
        if (node.children && node.children.length > 0) {
            node.children.forEach(child => collectKeysToRemove(child));
        }
    }

    // 遍历树结构，找到要删除的节点并收集其及子节点的 ID
    function traverseTree(nodes) {
        nodes.forEach(node => {
            if (Array.isArray(targetId) ? targetId.includes(node.id) : node.id === targetId) {
                collectKeysToRemove(node);
            } else if (node.children && node.children.length > 0) {
                traverseTree(node.children);
            }
        });
    }

    // 递归查找目标节点的所有上级节点的 ID
    function findParentIds(nodes, target, parents = []) {
        for (let node of nodes) {
            if (Array.isArray(target) ? target.includes(node.id) : node.id === target) {
                return parents;
            }
            if (node.children && node.children.length > 0) {
                const newParents = [...parents, node.id];
                const found = findParentIds(node.children, target, newParents);
                if (found.length > 0) {
                    return found;
                }
            }
        }
        return [];
    }

    traverseTree(treeData);

    // 收集目标节点的上级节点 ID 并添加到 keysToRemove 中
    if (Array.isArray(targetId)) {
        targetId.forEach(id => {
            const parentIds = findParentIds(treeData, id);
            keysToRemove = keysToRemove.concat(parentIds);
        });
    } else {
        const parentIds = findParentIds(treeData, targetId);
        keysToRemove = keysToRemove.concat(parentIds);
    }

    // 过滤掉需要移除的节点 ID
    return checkedKeys.filter(key => !keysToRemove.includes(key));
}

/**
 * 在树形数据中查找具有指定字段名和值的节点。
 * 支持传入单个值或值数组进行匹配。
 * 匹配成功的节点将去除其 `children` 属性后添加到结果数组中。
 * 
 * @param {Array} treeData - 树形数据，是一个包含节点对象的数组。每个节点对象可以有一个 `children` 属性，用于表示子节点数组。
 * @param {string} fieldName - 要匹配的字段名，即节点对象中的属性名。
 * @param {string|Array} value - 要匹配的值，可以是单个字符串或字符串数组。
 * @returns {Array} - 返回一个数组，包含所有匹配到的节点（去除 `children` 属性）。如果传入的 `value` 为空，则返回空数组。
 */
export function findNodes (treeData, fieldName, value) {
    // 如果传入的 value 为空，则直接返回空数组
    if (!value) return [];
    // 用于存储找到的匹配节点
    const result = [];
    // 遍历树形数据中的每个节点
    treeData.forEach(node => {
        // 标记当前节点是否匹配
        let isMatch = false;
        // 判断 value 是否为字符串
        if (typeof value === 'string') {
            // 如果当前节点的指定字段值等于传入的字符串值，则标记为匹配
            if (node[fieldName] === value) {
                isMatch = true;
            }
        } 
        // 判断 value 是否为数组
        else if (Array.isArray(value)) {
            // 如果当前节点的指定字段值存在于传入的数组中，则标记为匹配
            if (value.includes(node[fieldName])) {
                isMatch = true;
            }
        }
        // 如果当前节点匹配
        if (isMatch) {
            // 解构赋值，去除节点的 children 属性
            const { children, ...nodeWithoutChildren } = node;
            // 将去除 children 属性的节点添加到结果数组中
            result.push(nodeWithoutChildren);
        }
        // 如果当前节点有子节点
        if (node.children && node.children.length > 0) {
            // 递归调用 findNodes 函数，在子节点中继续查找匹配的节点，并将结果添加到结果数组中
            result.push(...findNodes(node.children, fieldName, value));
        }
    });
    // 返回结果数组
    return result;
}

/**
 * 在树形数据中搜索具有指定字段名且该字段值包含指定搜索值的节点。
 * 匹配成功的节点将去除其 `children` 属性后添加到结果数组中。
 * 
 * @param {Array} treeData - 树形数据，是一个包含节点对象的数组。每个节点对象可以有一个 `children` 属性，用于表示子节点数组。
 * @param {string} fieldName - 要搜索的字段名，即节点对象中的属性名。
 * @param {string} value - 要搜索的值，必须是字符串类型。
 * @returns {Array} - 返回一个数组，包含所有匹配到的节点（去除 `children` 属性）。如果传入的 `value` 为空，则返回空数组。
 */
export function searchNodes (treeData, fieldName, value) {
    // 如果传入的 value 为空，则直接返回空数组
    if (!value) return [];
    // 用于存储找到的匹配节点
    const result = [];
    // 定义一个递归函数，用于遍历树形数据
    const traverse = (nodes) => {
        // 遍历当前层级的所有节点
        nodes.forEach((node) => {
            // 如果当前节点的指定字段值包含传入的搜索值
            if (node[fieldName].includes(value)) {
                // 解构赋值，去除节点的 children 属性
                const { children, ...nodeWithoutChildren } = node;
                // 将去除 children 属性的节点添加到结果数组中
                result.push(nodeWithoutChildren);
            }
            // 如果当前节点有子节点
            if (node.children && node.children.length > 0) {
                // 递归调用 traverse 函数，继续遍历子节点
                traverse(node.children);
            }
        });
    };
    // 从根节点开始调用 traverse 函数进行遍历
    traverse(treeData);
    // 返回结果数组
    return result;
};


/**
 * 从树形数据中获取所有节点（去除 children 属性）
 * @param {Array} treeData - 树形数据数组，每个节点可以包含 children 属性表示子节点
 * @returns {Array} - 包含所有节点（去除 children 属性）的数组
 */
export function getAllNodes(treeData) {
    let allNodes = [];
    const traverse = (nodeList) => {
        nodeList.forEach(node => {
            const { children, ...nodeWithoutChildren } = node;
            allNodes.push(nodeWithoutChildren); // 收集当前节点
            if (node.children) {
                traverse(node.children); // 递归遍历子节点
            }
        });
    };
    traverse(treeData);
    console.log('wyq-treeUtil-getAllNodes',allNodes);
    return allNodes;
}



// 封装成树形结构的公共方法
export function convertToTree (data) {
    // 用于存储每个节点的映射，键为节点的 id，值为节点对象
    const nodeMap = {};
    // 存储根节点的数组
    const tree = [];
    const localData = [];
    // 第一次遍历，将每个节点存储到 nodeMap 中
    data.forEach(item => {
        // 为每个节点添加 children 属性，用于存储其子节点
        item.children = [];
        // 去重处理， 同一个id只保留一个节点
        if (isEmpty(nodeMap[item.id])) {
            nodeMap[item.id] = item;
            localData.push(item);

        }
    });
    // 第二次遍历，构建树形结构
    localData.forEach(item => {
        const pid = item.pid;
        if (pid === null || pid === undefined || pid === item.id || !nodeMap[pid]) {
            // 如果 pid 为 null 或 undefined，或者父节点不存在，则将该节点作为根节点
            tree.push(item);
        } else {
            // 否则，将该节点添加到其父节点的 children 数组中
            nodeMap[pid].children.push(item);
        }
    });
    return tree;
}
