const { convertStringToJson } = require("./util");

const getAllProcesses = async (workflow, query = {}) => {
    const processes = await bpmsDB.bpms_process.findAll({
        where: {
            workflowId: workflow.id,
            ...query
            // type:{
            //     [Op.in]:[0,1]
            // }
        },
        order: [
            ['id', 'ASC']
        ],
        attributes: [
            "id", "pid", "link", "type", "name", "conditions", "subFlowPid", "subFlowId"
        ],
        raw: true
    });
    return processes;
}

function getProcessPaths(data, workflow) {
    const invalidPathsWithoutEnding = [];

    const nodesMap = data.reduce((map, node) => {
        map[node.id.toString()] = node;
        return map;
    }, {});

    const subFlowParentIds = [];
    // const childrenMap = data.reduce((map, node) => {
    //     const pid = node.pid;
    //     if (pid !== null && pid !== undefined) {
    //       if (!map[pid]) map[pid] = [];
    //       map[pid].push(node);
    //     }
    //     return map;
    // }, {});

    const startNodes = data.filter(node => ((node.type === 0 || node.type === 1) && node.pid === null));

    // console.log("startNodes", startNodes)

    if (startNodes?.length === 0 || !startNodes) {
        // invalidPathsWithoutEnding.push({ path: null, data: null, workflow: workflow.id, error: "هیچ پروسسی برای استارت این ورک فلو وجود ندارد" });
        invalidPathsWithoutEnding.push("هیچ پروسسی برای استارت این ورک فلو وجود ندارد");
        return {
            allPaths: [],
            subFlowParentIds: [],
            invalidPathsWithoutEnding
        };
    }

    let allPaths = [];
    const pathSet = new Set(); //for delete duplicated paths
    function isUniquePath(path) {
        const pathString = path.map(n => n.id).join(',');
        if (pathSet.has(pathString)) return false;
        pathSet.add(pathString);
        return true;
    }

    function traverse(currentNode, currentPath, visited) {
        // if (currentNode.type === 99) { // in bekhatere in ezaf shod ke mikhastim gozaresh ha ro nadide begirim felan
        //     if(isUniquePath([...currentPath])){
        //         // allPaths.push({path:[...currentPath].map(n => n.id),data:mergedData});
        //         invalidPathsWithoutEnding.push({path:[...currentPath].map(n => n.id),data:mergedData});
        //     }
        //     return;
        // }
        // const date = Date.now();
        // console.time(date);
        const newPath = [...currentPath, currentNode];
        const newVisited = { ...visited };

        const nodeIdStr = currentNode.id.toString();
        const visitCount = newVisited[nodeIdStr] || 0;

        if (visitCount >= 2) {
            // console.timeEnd(date);
            return;
        }
        newVisited[nodeIdStr] = visitCount + 1;


        // const newMergedData = [...mergedData]
        // newMergedData.push({
        //     processId: currentNode.id.toString(),
        //     // condition: convertStringToJson(currentNode.conditions)
        // });


        if (currentNode.type === 99 || currentNode.type === 100 || currentNode.subFlowPid) {
            if (currentNode.subFlowPid && !subFlowParentIds.includes(currentNode.subFlowPid)) subFlowParentIds.push(currentNode.subFlowPid)
            // allPaths.push(newPath.map(n => n.id));
            if (isUniquePath(newPath)) {
                allPaths.push(newPath.map(n => n.id).join(","));
            }
            // console.timeEnd(date);
            return;
        }

        const children = data.filter(node => node.pid == nodeIdStr);
        // console.log("3 data:",children,nodeIdStr,data)
        const linkNodes = [];

        if (currentNode.link) {
            currentNode.link.split(',').forEach(id => {
                const linkedNode = nodesMap[id];
                if (linkedNode) {
                    linkNodes.push(linkedNode);
                }
            });
        }

        const nextNodes = [...children, ...linkNodes];

        // console.timeEnd(date);
        if (nextNodes?.length === 0) {
            if (isUniquePath(newPath)) {
                // allPaths.push({path:newPath.map(n => n.id),data:newMergedData});
                invalidPathsWithoutEnding.push(newPath.map(n => n.id).join(","));
            }
            return;
        }

        nextNodes.forEach(nextNode => {
            traverse(nextNode, newPath, newVisited);
        });
    }

    for (let startNode of startNodes) {
        traverse(startNode, [], {});
    }

    // console.log("allPaths:",allPaths.length);


    // allPaths = [...new Set(
    //   allPaths.map((path,pindex)=>{
    //     return path.path.join(",")
    //   })
    // )].map((newPath,index)=>{
    //   return newPath.split(",")
    // })

    // console.log("allPaths after:",allPaths.length);

    // return allPaths.map((a,aindex)=>{
    //   return a.map((b,bindex)=>{
    //     return nodesMap[b.toString()].name
    //   })
    // });

    return { allPaths, subFlowParentIds, invalidPathsWithoutEnding };
}

function getProcessPathsSubFlow(data, subFlowIdTemp, workflow) {

    const invalidSubPathsWithoutEnding = [];

    const nodesMap = data.reduce((map, node) => {
        map[node.id.toString()] = node;
        return map;
    }, {});


    // const childrenMap = data.reduce((map, node) => {
    //     const pid = node.pid;
    //     if (pid !== null && pid !== undefined) {
    //       if (!map[pid]) map[pid] = [];
    //       map[pid].push(node);
    //     }
    //     return map;
    // }, {});

    let subTreePath = [];

    const startNodes = data.filter(node => ((node.type === 0 || node.type === 1) && node.pid === null) || (node.subFlowPid == subFlowIdTemp));

    // console.log("startNodes",startNodes)

    if (startNodes?.length === 0 || !startNodes) {
        //   return [];
        // invalidSubPathsWithoutEnding.push({ path: null, data: null, workflow: workflow.id, subworkflow: subFlowIdTemp, error: "هیچ پروسس استارتی برای این ورک فلو وجود ندارد" });
        invalidSubPathsWithoutEnding.push("هیچ پروسس استارتی برای این ورک فلو وجود ندارد");
        return {
            subTreePath: [],
            invalidSubPathsWithoutEnding
        };
    }

    const pathSet = new Set(); //for delete duplicated paths
    function isUniquePath(path) {
        const pathString = path.map(n => n.id).join(',');
        if (pathSet.has(pathString)) return false;
        pathSet.add(pathString);
        return true;
    }

    function traverse(currentNode, currentPath, visited) {
        // if (currentNode.type === 99) { // in bekhatere in ezaf shod ke mikhastim gozaresh ha ro nadide begirim felan
        //     if(isUniquePath([...currentPath])){
        //         // allPaths.push({path:[...currentPath].map(n => n.id),data:mergedData});
        //         invalidPathsWithoutEnding.push({path:[...currentPath].map(n => n.id),data:mergedData});
        //     }
        //     return;
        // }
        // const date = `sub${subFlowIdTemp}-${Date.now()}`;
        // console.time(date);
        const newPath = [...currentPath, currentNode];
        const newVisited = { ...visited };

        const nodeIdStr = currentNode.id.toString();
        const visitCount = newVisited[nodeIdStr] || 0;

        if (visitCount >= 2) {
            // console.timeEnd(date);
            return;
        }
        newVisited[nodeIdStr] = visitCount + 1;


        // const newMergedData = [...mergedData]
        // newMergedData.push({
        //     processId: currentNode.id.toString(),
        //     // condition: convertStringToJson(currentNode.conditions)
        // });


        if (currentNode.type === 99 || currentNode.type === 100
            // || currentNode.subFlowPid  it will be uncommented when we want go to final subflowPid
        ) {
            // allPaths.push(newPath.map(n => n.id));
            if (isUniquePath(newPath)) {
                subTreePath.push( newPath.map(n => n.id).join(","));
            }
            // console.timeEnd(date);
            return;
        }

        const children = data.filter(node => node.pid == nodeIdStr);
        // console.log("3 data:",children,nodeIdStr,data)
        const linkNodes = [];

        if (currentNode.link) {
            currentNode.link.split(',').forEach(id => {
                const linkedNode = nodesMap[id];
                if (linkedNode) {
                    linkNodes.push(linkedNode);
                }
            });
        }

        const nextNodes = [...children, ...linkNodes];

        // console.timeEnd(date);

        if (nextNodes?.length === 0) {
            if (isUniquePath(newPath)) {
                // allPaths.push({path:newPath.map(n => n.id),data:newMergedData});

                invalidSubPathsWithoutEnding.push(newPath.map(n => n.id).join(",")
                        //  data: newMergedData,
                        // error: "هیچ پروسس پایانی برای این ورک فلو وجود ندارد"
                );
            }
            return;
        }


        nextNodes.forEach(nextNode => {
            traverse(nextNode, newPath, newVisited);
        });


    }

    for (let startNode of startNodes) {
        traverse(startNode, [], {});
    }

    // console.log("allPaths:",allPaths.length);
    // console.log("allPaths:",allPaths.length);


    // allPaths = [...new Set(
    //   allPaths.map((path,pindex)=>{
    //     return path.path.join(",")
    //   })
    // )].map((newPath,index)=>{
    //   return newPath.split(",")
    // })

    // console.log("allPaths after:",allPaths.length);

    // return allPaths.map((a,aindex)=>{
    //   return a.map((b,bindex)=>{
    //     return nodesMap[b.toString()].name
    //   })
    // });

    return { subTreePath, invalidSubPathsWithoutEnding };
}

module.exports = {
    getAllProcesses,
    getProcessPaths,
    getProcessPathsSubFlow
}