class Status_UnitPubilcV3 {
    constructor() { }
    get_param_of_turn(query, ret) {
        let turns = [
            {
                raw_query: ret.responses[0].raw_query,
                service_id: ret.service_id,
                skill_ids: ret.skill_ids,
                SYS_TRACES: ret.context.SYS_TRACES, //参考一下截屏的SYS_TRACES部分
                SYS_VARS: ret.context.SYS_VARS, //参考一下截屏的SYS_TRACES部分
                actions: ret.responses[0].actions, //参考一下截屏的actions部分
            },
        ];

        return turns;
    }

    getMatch(array1, array2) {
        return array1.filter((object1) => {
            return array2.some((object2) => {
                return (
                    object1.node_name === object2.action_id ||
                    object2.action_id.startsWith(object1.node_name)
                );
            });
        });
    }
    getNodeInfo(actions, node,turn) {
        var result = {
            name: node.node_name,
            type: node.node_type,
            id: node.node_id,
            count: node.count,
            botId:turn.service_id,
            actions: actions
        }
        return result;
    }

    // 预处理
    async Pretreatment(obj) {
        let param = {};
        let turn = { ...obj };
        let nodes = turn.SYS_TRACES;
        this.getNodeCount(turn);
        let link_len = nodes.filter((item) => item.node_type == "link").length;
        let node_len = nodes.length - link_len;
        let action_len = turn.actions.length;
        //bot_failure
        let bot_failure = this.get_bot_failure(turn);
        let diff = this.get_bot_failure_diff(turn);
        turn.SYS_TRACES = diff.nodes;
        turn.actions = diff.actions;
        //bot_timeout
        let bot_timeout = this.get_bot_timeout(turn);
        if (bot_timeout) {
            diff = bot_timeout.diff;
            delete bot_timeout.diff;
            turn.SYS_TRACES = diff.nodes;
            turn.actions = diff.actions;
        }
        //bot_final
        let bot_final = this.get_bot_final(turn);
        diff = this.get_bot_final_diff(turn);
        turn.SYS_TRACES = diff.nodes;
        turn.actions = diff.actions;
        //bot_terminate
        let bot_terminate = this.get_bot_terminate(turn);
        diff = this.get_bot_terminate_diff(turn);
        turn.SYS_TRACES = diff.nodes;
        turn.actions = diff.actions;
        // taskflows
        turn = this.turnClean(turn);
        let kw = await this.getKw(turn);
        diff = this.getKwDiff(turn);
        turn.SYS_TRACES = diff.nodes;
        turn.actions = diff.actions;
        //kw
        kw.bot_terminate = bot_terminate;
        kw.bot_final = bot_final;
        kw.bot_timeout = bot_timeout;


        let taskflows = await this.getTaskflows(turn);
        diff = await this.getDiff(turn);
        turn.SYS_TRACES = diff.nodes;
        turn.actions = diff.actions;

        let exeption = await this.getExeption(turn);
        if (bot_failure.length > 0) {
            if (exeption) {
                exeption.fail = bot_failure;
            } else {
                exeption = {
                    fail: bot_failure
                }
            }
        }

        diff = this.getExeptionDiff(turn);
        turn.SYS_TRACES = diff.nodes;
        turn.actions = diff.actions;

        param = {
            summary: {
                SYS_VARS:obj.SYS_VARS,
                link_len,
                node_len,
                action_len,
            },
            taskflows,
            kw,
            exeption,
            diff,
        };

        return param;
    }
    // 过滤link
    turnClean(turn) {
        let nodes = turn.SYS_TRACES.filter((x) => x.node_type != "link");
        turn.SYS_TRACES = nodes;
        return turn;
    }
    // expetion处理
    getExeption(turn) {
        let ret = {};
        ret.confidence_lows = turn.actions.filter((x) => x.confidence == 0);
        if (ret.confidence_lows.length > 0) {
            return ret;
        }
        ret.fail_actions = turn.actions.filter((x) => x.action_id == "fail_action");
        if (ret.fail_actions.length > 0) {
            return ret;
        }
        ret.failures = turn.actions.filter((x) => x.type == "failure");
        if (ret.failures.length > 0) {
            return ret;
        }
    }
    getExeptionDiff(turn) {
        let diff = {};
        diff.actions = turn.actions.filter((x) => x.confidence !== 0);

        diff.actions = diff.actions.filter((x) => x.action_id !== "fail_action");

        diff.actions = diff.actions.filter((x) => x.type !== "failure");
        diff.nodes = turn.SYS_TRACES;
        return diff;
    }

    // kw处理
    getKw(turn) {
        let kw = {};
        let nodes = turn.SYS_TRACES.filter(
            (x) => x.node_name == "faq" || x.node_name == "kbqa"
        );
        let actions = turn.actions.filter(
            (x) => x.action_id.startsWith("faq_") || x.action_id.startsWith("kbqa_")
        );

        nodes.forEach((item, ind) => {
            if (actions.length > 0) {
                kw[item.node_name] = this.getNodeInfo(actions, item,turn);
            }

        });

        return kw;
    }
    getKwDiff(turn) {
        let diff = {};
        diff.actions = turn.actions.filter(
            (x) =>
                !(x.action_id.startsWith("faq_") || x.action_id.startsWith("kbqa_"))
        ); //差集
        diff.nodes = turn.SYS_TRACES.filter(
            (x) => !(x.node_name == "faq" || x.node_name == "kbqa")
        );
        return diff;
    }

    // bot处理
    get_bot_failure(turn) {
        let result = [];
        var actions = turn.actions.filter((x) => x.action_id == "失败");
        result = actions;
        return result;
    }
    get_bot_failure_diff(turn) {
        let diff = {};
        diff.actions = turn.actions.filter((x) => x.action_id !== "失败");
        diff.nodes = turn.SYS_TRACES.filter((x) => !(x.node_name == "失败" && x.node_type == 'reply'));
        return diff;
    }
    get_bot_timeout(turn) {
        // bot_timeout
        // raw_query=='timeout' && ((action_type in【clarify】, node_type in [slot_filling,yes_no]) || (action_type in【guide】, node_type in [select]))    
        let result;
        let raw_query = turn.raw_query;
        if (raw_query === "timeout") {
            var clarify = turn.actions.filter(
                (x) => turn.SYS_TRACES.find(
                    (y) => (x.action_id === y.node_name || x.action_id.startsWith(y.node_name)) && isIn(["clarify"], x.type) && isIn(["slot_filling", "yes_no"], y.node_type)
                )
            );
            var guide = turn.actions.filter(
                (x) => turn.SYS_TRACES.find(
                    (y) => (x.action_id === y.node_name || x.action_id.startsWith(y.node_name)) && isIn(["guide"], x.type) && isIn(["select"], y.node_type)
                )
            );
            var satisfy = turn.actions.filter(
                (x) => turn.SYS_TRACES.find(
                    (y) => x.action_id === y.node_name && x.action_id.startsWith("wait_of_") && y.node_type === "reply"
                )
            );
            if (clarify.length > 0 || guide.length > 0 || satisfy.length > 0) {
                result = {
                    count: 0,//超时几次，与当前节点配套
                    actions: []
                };
                if (clarify.length > 0) {
                    let node = this.getActionNode(clarify[0], turn.SYS_TRACES)
                    result = this.getNodeInfo(clarify, node,turn);
                }
                if (guide.length > 0) {
                    let node = this.getActionNode(guide[0], turn.SYS_TRACES)
                    result = this.getNodeInfo(guide, node,turn);
                }
                if (satisfy.length > 0) {
                    let node = this.getActionNode(satisfy[0], turn.SYS_TRACES)
                    result = this.getNodeInfo(satisfy, node,turn);
                }
                //diff
                let diff = {};
                var actions = turn.actions.filter(
                    (x) => !(clarify.find(
                        (y) => y.action_id === x.action_id
                    ) || guide.find(
                        (y) => y.action_id === x.action_id
                    ) || satisfy.find(
                        (y) => y.action_id === x.action_id
                    ))
                );
                let nodes = turn.SYS_TRACES.filter(
                    (x) => !(clarify.find(
                        (y) => y.action_id === x.node_name
                    ) || guide.find(
                        (y) => y.action_id === x.node_name
                    ) || satisfy.find(
                        (y) => y.action_id === x.node_name
                    ))
                );
                diff.actions = actions;
                diff.nodes = nodes;
                result.diff = diff;
            }
        }
        return result;
    }
    getActionNode(action, nodes) {

        let node = nodes.filter((x) => x.node_name === action.action_id || action.action_id.startsWith(x.node_name));
        return node[0];
    }
    get_bot_final(turn) {
        // bot_final
        let result;
        var actions = turn.actions.filter((x) => x.action_id.startsWith('final_'));
        if (actions.length > 0) {
            let node = this.getActionNode(actions[0], turn.SYS_TRACES)
            result = this.getNodeInfo(actions, node,turn);
        }
        return result;
    }
    get_bot_final_diff(turn) {
        let diff = {};
        diff.actions = turn.actions.filter((x) => !x.action_id.startsWith('final_'));
        diff.nodes = turn.SYS_TRACES.filter((x) => !x.node_name.startsWith('final_'));
        return diff;
    }
    get_bot_terminate(turn) {
        // bot_terminate
        let result;
        var actions = turn.actions.filter((x) => x.action_id.startsWith('end_'));
        if (actions.length > 0) {
            let node = this.getActionNode(actions[0], turn.SYS_TRACES)
            result = this.getNodeInfo(actions, node,turn);
            result.reason = turn.SYS_VARS.reason;
        }
        return result;
    }
    get_bot_terminate_diff(turn) {
        let diff = {};
        diff.actions = turn.actions.filter((x) => !x.action_id.startsWith('end_'));
        diff.nodes = turn.SYS_TRACES.filter((x) => !(x.node_name.startsWith('end_') || x.node_name.startsWith('terminate_')));
        return diff;
    }

    // taskflows处理
    getTaskflows(turn) {
        let matchNodes = this.getMatch(turn.SYS_TRACES, turn.actions);

        let actions = [];
        let obj = {};
        for (let k in matchNodes) {
            let action = turn.actions.filter(
                (x) =>
                    x.action_id == matchNodes[k].node_name ||
                    x.action_id.startsWith(matchNodes[k].node_name)
            );
            obj=this.getNodeInfo(action,matchNodes[k],turn)
            actions.push(obj);
        }
        /* let slot_fillings = turn.SYS_TRACES.filter(
          (x) => x.node_type == "slot_filling"
        );
        actions.push(slot_fillings); */
        return actions;
    }
    getDiff(turn) {
        let diff = {};

        diff.nodes = turn.SYS_TRACES.filter(
            (x) =>
                !turn.actions.find(
                    (y) =>
                        y.action_id === x.node_name || y.action_id.startsWith(x.node_name)
                )
        );

        diff.actions = turn.actions.filter(
            (x) =>
                !turn.SYS_TRACES.find(
                    (y) =>
                        y.node_name === x.action_id || x.action_id.startsWith(y.node_name)
                )
        ); //差集

        return diff;
    };
    getNodeCount(turn) {
        if (turn.SYS_VARS?.SYS_BUILT?.node_passing_times) {
            for (var item of turn.SYS_VARS.SYS_BUILT.node_passing_times) {
                for (var node of turn.SYS_TRACES) {
                    let obj = {...node};
                    if (item.node_id === node.node_id) {
                        obj.count = item.count;
                        node = obj;
                    }
                }
            }
        }
    }



}

//判断是否在数组中
function isIn(list, target) {
    for (var item of list) {
        if (item == target) {
            return true;
        }
    }
    return false;
}

function is_empty(obj) {
    if (obj == null) {
        return true;
    }
    var arr = Object.keys(obj);
    return arr.length == 0;
}
exports.Status_UnitPubilcV3 = Status_UnitPubilcV3;