package com.kingdee.eas.custom.perfweb.utils;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.metadata.entity.*;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.eas.base.message.util.StringUtil;
import com.kingdee.eas.base.permission.IUser;
import com.kingdee.eas.base.permission.UserCollection;
import com.kingdee.eas.base.permission.UserFactory;
import com.kingdee.eas.base.permission.UserInfo;
import com.kingdee.eas.basedata.person.IPerson;
import com.kingdee.eas.basedata.person.PersonCollection;
import com.kingdee.eas.basedata.person.PersonFactory;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.shr.perfweb.app.base.evalplan.IPerfEvaObject;
import com.kingdee.shr.perfweb.app.base.evalplan.ITargetNode;
import com.kingdee.shr.perfweb.app.base.evalplan.PerfEvaObjectCollection;
import com.kingdee.shr.perfweb.app.base.evalplan.PerfEvaObjectFactory;
import com.kingdee.shr.perfweb.app.base.evalplan.PerfEvaObjectInfo;
import com.kingdee.shr.perfweb.app.base.evalplan.TargetNodeCollection;
import com.kingdee.shr.perfweb.app.base.evalplan.TargetNodeFactory;
import com.kingdee.shr.perfweb.app.base.evalplan.TargetNodeInfo;
import com.kingdee.shr.perfweb.app.base.evalrule.IWFNodeDef;
import com.kingdee.shr.perfweb.app.base.evalrule.WFNodeDefCollection;
import com.kingdee.shr.perfweb.util.PersonInchargeUtils;
import com.kingdee.shr.perfweb.app.base.evalrule.WFNodeDefFactory;
import com.kingdee.shr.perfweb.app.base.evalrule.WFNodeDefInfo;
import com.kingdee.shr.perfweb.app.workflow.GradeTaskNodeInstCollection;
import com.kingdee.shr.perfweb.app.workflow.GradeTaskNodeInstFactory;
import com.kingdee.shr.perfweb.app.workflow.GradeTaskNodeInstInfo;
import com.kingdee.shr.perfweb.app.workflow.IGradeTaskNodeInst;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
 * 类名称: PerfPlanExecuteUtils
 * 功能描述: 考核对接工具类
 * 创建日期: 2026-06-11 10:01
 * 作    者: 青梧
 * 版    本: 1.0
 */
public class PerfEvaObjectUtil {
    private static Logger logger = LoggerFactory.getLogger("com.kingdee.eas.custom.perfweb.utils.PerfEvaObjectUtils");

    /***
     *获取评分任务节点实例
     */
    public static GradeTaskNodeInstInfo getGradeTaskNodeInst(Context ctx, String evaObjId, String wfLevel) throws BOSException {
        FilterInfo filter = new FilterInfo();
        filter.getFilterItems().add(new FilterItemInfo("evaObj", evaObjId, CompareType.EQUALS));
        filter.getFilterItems().add(new FilterItemInfo("wfLevel", wfLevel, CompareType.EQUALS));
        EntityViewInfo evi = new EntityViewInfo();
        evi.setFilter(filter);
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add(new SelectorItemInfo("id"));
        sic.add(new SelectorItemInfo("nodeHandler.number"));
        sic.add(new SelectorItemInfo("nodeHandler.id"));
        evi.setSelector(sic);
        IGradeTaskNodeInst igradeTaskNodeInst = GradeTaskNodeInstFactory.getLocalInstance(ctx);
        GradeTaskNodeInstCollection coll = igradeTaskNodeInst.getGradeTaskNodeInstCollection(evi);
        if (coll == null || coll.isEmpty()) {
            return null;
        }
        return coll.get(0);
    }

    /**
     * 获取评分任务节点实例主键（flowId）
     */
    public static String getGradeTaskNodeInstId(Context ctx, String evaObjId, int wfLevel) {
        try {
            GradeTaskNodeInstInfo info = getGradeTaskNodeInst(ctx, evaObjId, String.valueOf(wfLevel));
            if (info != null && info.getId() != null) {
                return info.getId().toString();
            }
        } catch (BOSException e) {
            logger.error("getGradeTaskNodeInstId failed, evaObjId=" + evaObjId + ", wfLevel=" + wfLevel, e);
        }
        return null;
    }

    /**
     * 获取节点处理人工号
     */
    public static String getNodeHandlerNumber(GradeTaskNodeInstInfo info) {
        if (info != null && info.getNodeHandler() != null && StringUtils.isNotBlank(info.getNodeHandler().getNumber())) {
            return info.getNodeHandler().getNumber();
        }
        return null;
    }

    /**
     * 启动考核飞书专用：仅按「设置评分人」T_EVA_TargetNode 取处理人，不读 GradeTaskNodeInst。
     */
    public static void getBatchTargetNodeHandlersForEvaObj(Context ctx, Set<String> evaObjSet, Map<String, String> resultMap,
            Map<String, Set<String>> evaObjHandlerMap, Map<String, String> workFlowNameMap, String wfLevel) {
        if (CollectionUtils.isEmpty(evaObjSet)) {
            return;
        }
        try {
            int level = Integer.parseInt(wfLevel);
            if (level < 1) {
                logger.error("TargetNode 查评分人跳过，wfLevel无效: {}", wfLevel);
                return;
            }
            Set<String> allHandlerIdSet = new HashSet();
            Map<String, String> evaObjWorkFlowIdMap = loadEvaObjWorkFlowIdMap(ctx, evaObjSet, workFlowNameMap);
            for (String evaObjId : evaObjSet) {
                if (StringUtils.isBlank(evaObjId)) {
                    continue;
                }
                String workFlowId = evaObjWorkFlowIdMap.get(evaObjId);
                if (StringUtils.isBlank(workFlowId)) {
                    logger.error("TargetNode 查评分人跳过，未找到考核对象流程, evaObjId={}", evaObjId);
                    continue;
                }
                Set<String> handlerNumbers = new LinkedHashSet<>();
                StringBuilder nameBuilder = new StringBuilder();
                resolveHandlersFromTargetNode(ctx, evaObjId, workFlowId, level, handlerNumbers, nameBuilder, allHandlerIdSet);
                if (handlerNumbers.isEmpty()) {
                    logger.error("TargetNode 未配置评分人, evaObjId={}", evaObjId);
                    continue;
                }
                String key = evaObjId + "$" + workFlowId;
                evaObjHandlerMap.put(key, handlerNumbers);
                if (nameBuilder.length() > 0) {
                    resultMap.put(key, nameBuilder.toString());
                }
                logger.error("TargetNode 查评分人成功, evaObjId={}, handlers={}", evaObjId, handlerNumbers);
            }
            enrichHandlerDisplayNames(ctx, allHandlerIdSet, evaObjHandlerMap, resultMap);
        } catch (Exception e) {
            logger.error("getBatchTargetNodeHandlersForEvaObj failed", e);
        }
    }

    private static void enrichHandlerDisplayNames(Context ctx, Set<String> allHandlerIdSet,
            Map<String, Set<String>> evaObjHandlerMap, Map<String, String> resultMap) throws BOSException {
        if (CollectionUtils.isEmpty(allHandlerIdSet) || CollectionUtils.isEmpty(evaObjHandlerMap)) {
            return;
        }
        FilterInfo userFilterAll = new FilterInfo();
        userFilterAll.getFilterItems().add(new FilterItemInfo("person", allHandlerIdSet, CompareType.INCLUDE));
        userFilterAll.getFilterItems().add(new FilterItemInfo("isDelete", 0, CompareType.EQUALS));
        EntityViewInfo userEvi = new EntityViewInfo();
        SelectorItemCollection userSic = new SelectorItemCollection();
        userSic.add(new SelectorItemInfo("id"));
        userSic.add(new SelectorItemInfo("person.id"));
        userSic.add(new SelectorItemInfo("person.number"));
        userSic.add(new SelectorItemInfo("person.name"));
        userEvi.setSelector(userSic);
        userEvi.setFilter(userFilterAll);
        IUser iUser = UserFactory.getLocalInstance(ctx);
        UserCollection userColl = iUser.getUserCollection(userEvi);
        if (userColl == null || userColl.size() <= 0) {
            return;
        }
        Map<String, PersonInfo> umap = new HashMap();
        for (int i = 0; i < userColl.size(); ++i) {
            UserInfo userInfo = userColl.get(i);
            if (userInfo != null && userInfo.getPerson() != null) {
                PersonInfo person = userInfo.getPerson();
                if (!StringUtil.isEmpty(person.getNumber())) {
                    umap.put(person.getNumber(), person);
                }
            }
        }
        for (Map.Entry<String, Set<String>> entry : evaObjHandlerMap.entrySet()) {
            String key = entry.getKey();
            Set<String> value = entry.getValue();
            if (StringUtils.isBlank(key) || CollectionUtils.isEmpty(value)) {
                continue;
            }
            StringBuilder sb = new StringBuilder();
            Set<String> waitDeleteIds = new HashSet();
            for (String pid : value) {
                PersonInfo personInfo = umap.get(pid);
                if (personInfo == null) {
                    waitDeleteIds.add(pid);
                } else if (!StringUtil.isEmpty(personInfo.getName(ctx.getLocale()))) {
                    sb.append(personInfo.getName()).append(",");
                }
            }
            if (!CollectionUtils.isEmpty(waitDeleteIds)) {
                value.removeAll(waitDeleteIds);
            }
            if (sb.length() > 0) {
                resultMap.put(key, sb.toString());
            }
        }
        for (Map.Entry<String, String> entry : resultMap.entrySet()) {
            if (!StringUtils.isEmpty(entry.getValue()) && entry.getValue().endsWith(",")) {
                entry.setValue(entry.getValue().substring(0, entry.getValue().length() - 1));
            }
        }
    }

    public static void getBatchCurrentNodeHandersForEvaObj(Context ctx, Set<String> evaObjSet, Map<String, String> resultMap, Map<String, Set<String>> evaObjHandlerMap, Map<String, Set<String>> workNodeNameMap, Map<String, String> workFlowNameMap, String wfLevel) {
        FilterInfo filter = new FilterInfo();
        filter.getFilterItems().add(new FilterItemInfo("evaObj.id", evaObjSet, CompareType.INCLUDE));
//        filter.getFilterItems().add(new FilterItemInfo("isEffective", "1", CompareType.EQUALS));
//        filter.getFilterItems().add(new FilterItemInfo("taskStatus", "2", CompareType.NOTEQUALS));
//        filter.getFilterItems().add(new FilterItemInfo("canEdit", "1", CompareType.EQUALS));
//        filter.getFilterItems().add(new FilterItemInfo("wfNode.workFlow.id", workFlowSet, CompareType.INCLUDE));
//        filter.getFilterItems().add(new FilterItemInfo("isRetain", "0", CompareType.EQUALS));
        filter.getFilterItems().add(new FilterItemInfo("wfLevel", wfLevel, CompareType.EQUALS));
        EntityViewInfo evi = new EntityViewInfo();
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add(new SelectorItemInfo("id"));
        sic.add(new SelectorItemInfo("evaObj.id"));
        sic.add(new SelectorItemInfo("nodeHandlerName"));
        sic.add(new SelectorItemInfo("nodeHandler.id"));
        sic.add(new SelectorItemInfo("nodeHandler.number"));
        sic.add(new SelectorItemInfo("wfNode.workFlow.*"));
        sic.add(new SelectorItemInfo("wfNode.*"));
        sic.add("wfNode.*");
        evi.setFilter(filter);
        evi.setSelector(sic);
        Set<String> allHandlerIdSet = new HashSet();
        Set<String> allWorkNodeIdSet = new HashSet();

        try {
            IGradeTaskNodeInst igradeTaskNodeInst = GradeTaskNodeInstFactory.getLocalInstance(ctx);
            GradeTaskNodeInstCollection coll = igradeTaskNodeInst.getGradeTaskNodeInstCollection(evi);
            if (coll != null && coll.size() > 0) {
                Set<String> workNodeIdSet = null;
                for (int i = 0; i < coll.size(); ++i) {
                    GradeTaskNodeInstInfo info = coll.get(i);
                    if (null != info.getNodeHandler() && null != info.getNodeHandler().getId()) {
                        allHandlerIdSet.add(info.getNodeHandler().getId().toString());
                        // 同时取工号用于后续匹配
                        if (null != info.getNodeHandler().getNumber()) {
                            allHandlerIdSet.add(info.getNodeHandler().getNumber());
                        }
                    }

                    String evaObj = info.getEvaObj().getId().toString();
                    String key = evaObj + "$" + info.getWfNode().getWorkflow().getId().toString();
                    // 填充 workFlowId → workFlowName（wfNode.workFlow.* 已在 selector 中）
                    if (workFlowNameMap != null && info.getWfNode().getWorkflow() != null) {
                        String wfId = info.getWfNode().getWorkflow().getId().toString();
                        if (!workFlowNameMap.containsKey(wfId)) {
                            String wfName = info.getWfNode().getWorkflow().getName();
                            if (StringUtils.isNotBlank(wfName)) {
                                workFlowNameMap.put(wfId, wfName);
                            }
                        }
                    }
                    if (info.getWfNode() != null && info.getWfNode().getId() != null) {
                        workNodeIdSet = (Set) workNodeNameMap.get(key);
                        if (CollectionUtils.isEmpty(workNodeIdSet)) {
                            workNodeIdSet = new HashSet();
                        }

                        workNodeIdSet.add(info.getWfNode().getId().toString());
                        allWorkNodeIdSet.add(info.getWfNode().getId().toString());
                    }

                    String handlers = (String) resultMap.get(key);
                    Set<String> handlerIdSet = (Set) evaObjHandlerMap.get(key);
                    if (CollectionUtils.isEmpty(handlerIdSet)) {
                        handlerIdSet = new HashSet(50);
                        if (null != info.getNodeHandler() && null != info.getNodeHandler().getNumber()) {
                            // 存工号而非ID，飞书接口接收人工号
                            handlerIdSet.add(info.getNodeHandler().getNumber());
                        }
                    } else if (null != info.getNodeHandler() && null != info.getNodeHandler().getNumber()) {
                        handlerIdSet.add(info.getNodeHandler().getNumber());
                    }

                    StringBuffer sb = null;
                    if (handlers == null) {
                        sb = new StringBuffer();
                    } else {
                        sb = new StringBuffer(handlers);
                    }

                    if (null != info.getNodeHandler() && !StringUtils.isEmpty(info.getNodeHandler().getName(ctx.getLocale()))) {
                        sb.append(info.getNodeHandler().getName(ctx.getLocale())).append(",");
                    }

                    resultMap.put(key, sb.toString());
                    evaObjHandlerMap.put(key, handlerIdSet);
                    workNodeNameMap.put(key, workNodeIdSet);
                }

                for (Map.Entry<String, String> entry : resultMap.entrySet()) {
                    if (!StringUtils.isEmpty((CharSequence) entry.getValue()) && ((String) entry.getValue()).lastIndexOf(",") == ((String) entry.getValue()).length() - 1) {
                        entry.setValue(((String) entry.getValue()).substring(0, ((String) entry.getValue()).length() - 1));
                    }
                }

                if (!CollectionUtils.isEmpty(allWorkNodeIdSet)) {
                    processNodeNameMap(allWorkNodeIdSet, workNodeNameMap, ctx);
                }
            }

            // 1) 节点实例(GradeTaskNodeInst)已有处理人 → 不再查评分人
            // 2) 无处理人 → 查 T_EVA_TargetNode（设置评分人）
            // 3) 仍无且一级 → 直接上级
            Set<String> needFallback = collectEvaObjWithoutHandler(evaObjSet, evaObjHandlerMap);
            System.out.println("needFallback---" + needFallback);
            if (!needFallback.isEmpty()) {
                fillWorkflowHandlerWhenNoNodeHandler(ctx, needFallback, resultMap, evaObjHandlerMap, workFlowNameMap, allHandlerIdSet, wfLevel);
            }

            enrichHandlerDisplayNames(ctx, allHandlerIdSet, evaObjHandlerMap, resultMap);
        } catch (BOSException e) {
            e.printStackTrace();
            logger.error("BOSException: ", e);
        }
    }

    /**
     * 节点实例未查到处理人时的兜底（仅处理 needFallback 中的考核对象）。
     * 1) T_EVA_TargetNode（设置评分人，多条取一条）
     * 2) 仍无且一级 → 职位直接上级
     */
    private static void fillWorkflowHandlerWhenNoNodeHandler(Context ctx, Set<String> needFallback, Map<String, String> resultMap, Map<String, Set<String>> evaObjHandlerMap, Map<String, String> workFlowNameMap, Set<String> allHandlerIdSet, String wfLevel) throws BOSException {
        if (CollectionUtils.isEmpty(needFallback)) {
            return;
        }

        int level;
        try {
            level = Integer.parseInt(wfLevel);
        } catch (NumberFormatException e) {
            logger.error("评分人兜底跳过，wfLevel无效: {}", wfLevel);
            return;
        }
        if (level < 1) {
            return;
        }

        logger.error("节点实例无处理人，查 T_EVA_TargetNode, wfLevel={}, evaObjIds={}", wfLevel, needFallback);
        System.out.println("节点实例无处理人，查 T_EVA_TargetNode, wfLevel={" + wfLevel + "}, evaObjIds={" + needFallback + "}");
        Map<String, String> evaObjWorkFlowIdMap = loadEvaObjWorkFlowIdMap(ctx, needFallback, workFlowNameMap);

        for (String evaObjId : needFallback) {
            String workFlowId = evaObjWorkFlowIdMap.get(evaObjId);
            if (StringUtils.isBlank(workFlowId)) {
                logger.error("TargetNode 兜底跳过，未找到考核对象流程, evaObjId={}", evaObjId);
                continue;
            }

            Set<String> handlerNumbers = new LinkedHashSet<>();
            StringBuilder nameBuilder = new StringBuilder();

            // 1) 设置评分人：T_EVA_TargetNode WHERE FEvaObjID=? AND FWfNodeID=?
            resolveHandlersFromTargetNode(ctx, evaObjId, workFlowId, level, handlerNumbers, nameBuilder, allHandlerIdSet);

            // 2) TargetNode 仍无，一级使用直接上级
            if (handlerNumbers.isEmpty() && level == 1) {
                logger.error("TargetNode 无评分人，使用直接上级兜底, evaObjId={}", evaObjId);
                fillDirectSuperiorFromPosition(ctx, evaObjId, handlerNumbers, nameBuilder, allHandlerIdSet);
            }

            if (handlerNumbers.isEmpty()) {
                logger.error("评分人兜底后仍为空, evaObjId={}, workFlowId={}", evaObjId, workFlowId);
                continue;
            }

            String key = evaObjId + "$" + workFlowId;
            evaObjHandlerMap.put(key, handlerNumbers);
            if (nameBuilder.length() > 0) {
                resultMap.put(key, nameBuilder.toString());
            }
            logger.error("评分人兜底成功, evaObjId={}, handlers={}", evaObjId, handlerNumbers);
        }
    }

    /**
     * 按 WFNodeDef 逐级查 T_EVA_TargetNode：evaObj.id + wfNode.id（WFNodeDef 主键）。
     * 等价 SQL：WHERE FEvaObjID = ? AND FWfNodeID = ?
     */
    private static void resolveHandlersFromTargetNode(Context ctx, String evaObjId, String workFlowId, int level, Set<String> handlerNumbers, StringBuilder nameBuilder, Set<String> allHandlerIdSet) {
        WFNodeDefCollection nodeDefs = loadWfNodeDefsForLevel(ctx, workFlowId, level);
        if (nodeDefs != null && !nodeDefs.isEmpty()) {
            for (int i = 0; i < nodeDefs.size(); i++) {
                WFNodeDefInfo nodeDef = nodeDefs.get(i);
                if (nodeDef == null || nodeDef.getId() == null) {
                    continue;
                }
                extractTargetNodeHandlers(ctx, evaObjId, nodeDef.getId().toString(), handlerNumbers, nameBuilder, allHandlerIdSet);
                if (!handlerNumbers.isEmpty()) {
                    return;
                }
            }
            return;
        }
        // 查不到 WFNodeDef 时，按考核对象查全部 TargetNode 行
        logger.error("未查到 WFNodeDef，按 evaObj 查全部 TargetNode, evaObjId={}, workFlowId={}, level={}", evaObjId, workFlowId, level);
        System.out.println("未查到 WFNodeDef，按 evaObj 查全部 TargetNode, evaObjId={" + evaObjId + "}, workFlowId={" + workFlowId + "}, level={" + level + "}");
        extractAllTargetNodeHandlersByEvaObj(ctx, evaObjId, handlerNumbers, nameBuilder, allHandlerIdSet);
    }

    /**
     * 仅按考核对象查 T_EVA_TargetNode（不限定 wfNode）
     */
    private static void extractAllTargetNodeHandlersByEvaObj(Context ctx, String evaObjId, Set<String> handlerNumbers, StringBuilder nameBuilder, Set<String> allHandlerIdSet) {
        try {
            FilterInfo filter = new FilterInfo();
            filter.getFilterItems().add(new FilterItemInfo("evaObj.id", evaObjId, CompareType.EQUALS));
            EntityViewInfo evi = new EntityViewInfo();
            evi.setFilter(filter);
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add(new SelectorItemInfo("personNumber"));
            sic.add(new SelectorItemInfo("personName"));
            evi.setSelector(sic);
            ITargetNode iTargetNode = TargetNodeFactory.getLocalInstance(ctx);
            TargetNodeCollection coll = iTargetNode.getTargetNodeCollection(evi);
            if (coll == null || coll.isEmpty()) {
                return;
            }
            for (int i = 0; i < coll.size(); i++) {
                TargetNodeInfo info = coll.get(i);
                if (info == null || StringUtils.isBlank(info.getPersonNumber())) {
                    continue;
                }
                appendHandler(info.getPersonNumber(), info.getPersonName(), handlerNumbers, nameBuilder, allHandlerIdSet);
                return;
            }
        } catch (BOSException e) {
            logger.error("按 evaObj 查 TargetNode 失败, evaObjId={}", evaObjId, e);
        }
    }

    private static WFNodeDefCollection loadWfNodeDefsForLevel(Context ctx, String workFlowId, int level) {
        try {
            FilterInfo filter = new FilterInfo();
            filter.getFilterItems().add(new FilterItemInfo("workflow.id", workFlowId, CompareType.EQUALS));
            filter.getFilterItems().add(new FilterItemInfo("level", level, CompareType.EQUALS));
            EntityViewInfo evi = new EntityViewInfo();
            evi.setFilter(filter);
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add(new SelectorItemInfo("id"));
            sic.add(new SelectorItemInfo("level"));
            sic.add(new SelectorItemInfo("nodeSeq"));
            sic.add(new SelectorItemInfo("nodeName"));
            sic.add(new SelectorItemInfo("nodeHandler"));
            evi.setSelector(sic);
            SorterItemCollection sorter = new SorterItemCollection();
            sorter.add(new SorterItemInfo("nodeSeq"));
            evi.setSorter(sorter);
            IWFNodeDef iwfNodeDef = WFNodeDefFactory.getLocalInstance(ctx);
            return iwfNodeDef.getWFNodeDefCollection(evi);
        } catch (BOSException e) {
            logger.error("查询 WFNodeDef 失败, workFlowId={}, level={}", workFlowId, level, e);
            return null;
        }
    }

    /**
     * T_EVA_TargetNode：evaObj + wfNodeId；同一节点多指标多行时，取第一条有效评分人
     */
    private static void extractTargetNodeHandlers(Context ctx, String evaObjId, String wfNodeId, Set<String> handlerNumbers, StringBuilder nameBuilder, Set<String> allHandlerIdSet) {
        try {
            FilterInfo filter = new FilterInfo();
            filter.getFilterItems().add(new FilterItemInfo("evaObj.id", evaObjId, CompareType.EQUALS));
            filter.getFilterItems().add(new FilterItemInfo("wfNode.id", wfNodeId, CompareType.EQUALS));
            EntityViewInfo evi = new EntityViewInfo();
            evi.setFilter(filter);
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add(new SelectorItemInfo("personNumber"));
            sic.add(new SelectorItemInfo("personName"));
            evi.setSelector(sic);
            ITargetNode iTargetNode = TargetNodeFactory.getLocalInstance(ctx);
            TargetNodeCollection coll = iTargetNode.getTargetNodeCollection(evi);
            if (coll == null || coll.isEmpty()) {
                return;
            }
            for (int i = 0; i < coll.size(); i++) {
                TargetNodeInfo info = coll.get(i);
                if (info == null || StringUtils.isBlank(info.getPersonNumber())) {
                    continue;
                }
                appendHandler(info.getPersonNumber(), info.getPersonName(), handlerNumbers, nameBuilder, allHandlerIdSet);
                return;
            }
        } catch (BOSException e) {
            logger.error("TargetNode 查询失败, evaObjId={}, wfNodeId={}", evaObjId, wfNodeId, e);
        }
    }

    private static void appendHandler(String personNumber, String personName, Set<String> handlerNumbers, StringBuilder nameBuilder, Set<String> allHandlerIdSet) {
        if (StringUtils.isNotBlank(personNumber)) {
            handlerNumbers.add(personNumber);
            allHandlerIdSet.add(personNumber);
        }
        if (StringUtils.isNotBlank(personName)) {
            if (nameBuilder.length() > 0) {
                nameBuilder.append(",");
            }
            nameBuilder.append(personName);
        }
    }

    private static void fillDirectSuperiorFromPosition(Context ctx, String evaObjId, Set<String> handlerNumbers, StringBuilder nameBuilder, Set<String> allHandlerIdSet) throws BOSException {
        Set<String> singleEvaObj = new HashSet<>();
        singleEvaObj.add(evaObjId);
        Map<String, Set<String>> superiorPersonIdMap = PersonInchargeUtils.getRelaPersonInchargeByids(ctx, singleEvaObj);
        if (superiorPersonIdMap == null || CollectionUtils.isEmpty(superiorPersonIdMap.get(evaObjId))) {
            return;
        }
        Map<String, PersonInfo> personById = loadPersonByIds(ctx, superiorPersonIdMap.get(evaObjId));
        for (String personId : superiorPersonIdMap.get(evaObjId)) {
            PersonInfo person = personById.get(personId);
            if (person == null || StringUtils.isBlank(person.getNumber())) {
                continue;
            }
            handlerNumbers.add(person.getNumber());
            allHandlerIdSet.add(person.getNumber());
            allHandlerIdSet.add(personId);
            if (!StringUtil.isEmpty(person.getName(ctx.getLocale()))) {
                if (nameBuilder.length() > 0) {
                    nameBuilder.append(",");
                }
                nameBuilder.append(person.getName(ctx.getLocale()));
            }
        }
    }

    private static Set<String> collectEvaObjWithoutHandler(Set<String> evaObjSet, Map<String, Set<String>> evaObjHandlerMap) {
        Set<String> needFallback = new HashSet<>();
        for (String evaObjId : evaObjSet) {
            if (StringUtils.isBlank(evaObjId)) {
                continue;
            }
            String prefix = evaObjId + "$";
            boolean hasHandler = false;
            if (evaObjHandlerMap != null) {
                for (Map.Entry<String, Set<String>> entry : evaObjHandlerMap.entrySet()) {
                    if (entry.getKey() != null && entry.getKey().startsWith(prefix) && !CollectionUtils.isEmpty(entry.getValue())) {
                        hasHandler = true;
                        break;
                    }
                }
            }
            if (!hasHandler) {
                needFallback.add(evaObjId);
            }
        }
        return needFallback;
    }

    private static Map<String, String> loadEvaObjWorkFlowIdMap(Context ctx, Set<String> evaObjIds, Map<String, String> workFlowNameMap) throws BOSException {
        Map<String, String> result = new HashMap<>();
        FilterInfo filter = new FilterInfo();
        filter.getFilterItems().add(new FilterItemInfo("id", evaObjIds, CompareType.INCLUDE));
        EntityViewInfo evi = new EntityViewInfo();
        evi.setFilter(filter);
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add(new SelectorItemInfo("id"));
        sic.add(new SelectorItemInfo("workFlow.id"));
        sic.add(new SelectorItemInfo("workFlow.name"));
        evi.setSelector(sic);

        IPerfEvaObject iPerfEvaObject = PerfEvaObjectFactory.getLocalInstance(ctx);
        PerfEvaObjectCollection coll = iPerfEvaObject.getPerfEvaObjectCollection(evi);
        if (coll == null || coll.isEmpty()) {
            return result;
        }
        for (int i = 0; i < coll.size(); i++) {
            PerfEvaObjectInfo info = coll.get(i);
            if (info == null || info.getId() == null || info.getWorkFlow() == null || info.getWorkFlow().getId() == null) {
                continue;
            }
            String evaObjId = info.getId().toString();
            String workFlowId = info.getWorkFlow().getId().toString();
            result.put(evaObjId, workFlowId);
            if (workFlowNameMap != null && !workFlowNameMap.containsKey(workFlowId)) {
                String wfName = info.getWorkFlow().getName();
                if (StringUtils.isNotBlank(wfName)) {
                    workFlowNameMap.put(workFlowId, wfName);
                }
            }
        }
        return result;
    }

    private static Map<String, PersonInfo> loadPersonByIds(Context ctx, Set<String> personIds) throws BOSException {
        Map<String, PersonInfo> result = new HashMap<>();
        if (CollectionUtils.isEmpty(personIds)) {
            return result;
        }
        FilterInfo filter = new FilterInfo();
        filter.getFilterItems().add(new FilterItemInfo("id", personIds, CompareType.INCLUDE));
        EntityViewInfo evi = new EntityViewInfo();
        evi.setFilter(filter);
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add(new SelectorItemInfo("id"));
        sic.add(new SelectorItemInfo("number"));
        sic.add(new SelectorItemInfo("name"));
        evi.setSelector(sic);

        IPerson iPerson = PersonFactory.getLocalInstance(ctx);
        PersonCollection coll = iPerson.getPersonCollection(evi);
        if (coll == null || coll.isEmpty()) {
            return result;
        }
        for (int i = 0; i < coll.size(); i++) {
            PersonInfo person = coll.get(i);
            if (person != null && person.getId() != null) {
                result.put(person.getId().toString(), person);
            }
        }
        return result;
    }

    private static void processNodeNameMap(Set<String> allWorkNodeIdSet, Map<String, Set<String>> workNodeNameMap, Context ctx) throws BOSException {
        FilterInfo nodeFilter = new FilterInfo();
        nodeFilter.getFilterItems().add(new FilterItemInfo("id", allWorkNodeIdSet, CompareType.INCLUDE));
        EntityViewInfo nodeEvi = new EntityViewInfo();
        SelectorItemCollection nodeSelector = new SelectorItemCollection();
        nodeSelector.add(new SelectorItemInfo("id"));
        nodeSelector.add(new SelectorItemInfo("nodeName"));
        nodeEvi.setFilter(nodeFilter);
        nodeEvi.setSelector(nodeSelector);
        WFNodeDefCollection nodeCollection = WFNodeDefFactory.getLocalInstance(ctx).getWFNodeDefCollection(nodeEvi);
        Map<String, String> nodeNameMap = new HashMap();
        int index = 0;

        for (int size = nodeCollection.size(); index < size; ++index) {
            WFNodeDefInfo info = nodeCollection.get(index);
            nodeNameMap.put(info.getId().toString(), info.getNodeName());
        }

        for (Map.Entry<String, Set<String>> entry : workNodeNameMap.entrySet()) {
            Set<String> nodeIdSet = (Set) entry.getValue();
            Set<String> newSet = new HashSet();

            for (String nodeId : nodeIdSet) {
                if (nodeNameMap.containsKey(nodeId)) {
                    newSet.add(nodeNameMap.get(nodeId));
                }
            }

            if (!CollectionUtils.isEmpty(newSet)) {
                entry.setValue(newSet);
            }
        }

    }
}
