package org.dromara.wflow.workflow.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.biz.domain.BizTask;
import org.dromara.biz.domain.BizTaskLog;
import org.dromara.biz.domain.bo.BizTaskBo;
import org.dromara.biz.domain.bo.BizTaskLogBo;
import org.dromara.biz.domain.vo.ActHiProcinstVo;
import org.dromara.biz.domain.vo.BizTaskLogVo;
import org.dromara.biz.mapper.*;
import org.dromara.biz.service.IBizTaskLogService;
import org.dromara.biz.service.IBizTaskService;
import org.dromara.common.core.constant.WflowContants;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.im.domain.ImGroup;
import org.dromara.im.mapper.ImGroupMapper;
import org.dromara.im.mapper.ImGroupMemberMapper;
import org.dromara.wflow.bean.do_.UserDeptDo;
import org.dromara.wflow.bean.do_.UserDo;
import org.dromara.wflow.bean.entity.WflowCcTasks;
import org.dromara.wflow.bean.entity.WflowFormRecord;
import org.dromara.wflow.bean.entity.WflowModelHistorys;
import org.dromara.wflow.bean.entity.WflowSubProcess;
import org.dromara.wflow.mapper.WflowCcTasksMapper;
import org.dromara.wflow.mapper.WflowModelHistorysMapper;
import org.dromara.wflow.mapper.WflowModelsMapper;
import org.dromara.wflow.mapper.WflowSubProcessMapper;
import org.dromara.wflow.service.OrgRepositoryService;
import org.dromara.wflow.utils.UserUtil;
import org.dromara.wflow.workflow.UELTools;
import org.dromara.wflow.workflow.bean.dto.ProcessInstanceOwnerDto;
import org.dromara.wflow.workflow.bean.process.OperationPerm;
import org.dromara.wflow.workflow.bean.process.OrgUser;
import org.dromara.wflow.workflow.bean.process.ProcessNode;
import org.dromara.wflow.workflow.bean.process.enums.ApprovalModeEnum;
import org.dromara.wflow.workflow.bean.process.enums.NodeTypeEnum;
import org.dromara.wflow.workflow.bean.process.enums.ProcessResultEnum;
import org.dromara.wflow.workflow.bean.process.form.Form;
import org.dromara.wflow.workflow.bean.process.props.ApprovalProps;
import org.dromara.wflow.workflow.bean.process.props.RootProps;
import org.dromara.wflow.workflow.bean.vo.*;
import org.dromara.wflow.workflow.config.WflowGlobalVarDef;
import org.dromara.wflow.workflow.service.*;
import org.dromara.wflow.workflow.utils.DeptIdUtil;
import org.flowable.engine.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RuansiMissionServiceImpl implements RuansiMissionService {

    @Value("${wflow.mission.default-title}")
    private String MISSION_TITLE;
    @Value("${wflow.mission.default-type}")
    private String MISSION_TYPE;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private UserDeptOrLeaderService userDeptOrLeaderService;

    @Autowired
    private ProcessInstanceService processInstanceService;

    @Autowired
    private OrgRepositoryService orgRepositoryService;

    @Autowired
    private WflowModelHistorysMapper modelHistorysMapper;

    @Autowired
    private ProcessNodeCatchService nodeCatchService;

    @Autowired
    private WflowSubProcessMapper subProcessMapper;

    @Autowired
    private WflowCcTasksMapper ccTasksMapper;

    @Autowired
    private IBizTaskService bizTaskService;

    @Autowired
    private UELTools uelTools;

    @Autowired
    private ActHiProcinstMapper actHiProcinstMapper;

    @Autowired
    private BusinessDataStorageService businessDataService;

    @Autowired
    private ProcessTaskService processTaskService;

    @Autowired
    private IBizTaskLogService iBizTaskLogService;

    @Autowired
    private BizTaskMapper bizTaskMapper;

    @Autowired
    private BizTaskWorkMapper bizTaskWorkMapper;

    @Autowired
    private BizTaskLogMapper bizTaskLogMapper;

    @Autowired
    private ImGroupMapper imGroupMapper;

    @Autowired
    private ImGroupMemberMapper imGroupMemberMapper;

    public static final String default_type_field = WflowContants.NORMAL_MISSION_DEFAULT_TYPE_FIELD;

    public static final String default_title_fieldId = WflowContants.NORMAL_MISSION_DEFAULT_TITLE_FIELD;

    public static final String default_level_fieldId = WflowContants.NORMAL_MISSION_DEFAULT_LEVEL_FIELD;

    @Override
    public TableDataInfo<RuansiMissionTaskVo> getUserSubmittedList(Integer pageSize, Integer pageNo, Long startUserId, String code, String[] startTimes, String taskType, String title, String status, String deptId, String level) {
        Boolean finished = null;
        if (status.equals("3") || status.equals("2")) {
            finished = false;
        } else if (status.equals("4")) {
            finished = true;
        }
        if (StringUtils.isNotBlank(deptId)) {
            deptId = DeptIdUtil.subDeptIdLastZero(deptId);
        }
        PageQuery pageQuery = new PageQuery();
        pageQuery.setPageNum(pageNo);
        pageQuery.setPageSize(pageSize);
        List<Long> userIds = Collections.singletonList(startUserId);
        Page<ActHiProcinstVo> historicProcessInstances = actHiProcinstMapper.selectMySubmmitedList(pageQuery.build(), null, userIds, code, startTimes, title, taskType, default_type_field, default_title_fieldId, finished, null, deptId, default_level_fieldId, level);

        Page<RuansiMissionTaskVo> page = new Page<>();
        page.setTotal(historicProcessInstances.getTotal());
        page.setCurrent(pageNo);
        page.setSize(pageSize);
//        Map<String, String> instanceNodeMap = new HashMap<>();
        page.setRecords(getInstanceList(historicProcessInstances.getRecords()));
        return TableDataInfo.build(page);
    }

    private List<RuansiMissionTaskVo> getInstanceList(List<ActHiProcinstVo> records) {
        List<String> instanceIds = records.stream().map(ActHiProcinstVo::getProcInstId).collect(Collectors.toList());
        Map<String,String> map = new HashMap<>();
        if(CollectionUtil.isNotEmpty(instanceIds)){

            List<BizTask> bizTasks = bizTaskMapper.selectList(new LambdaQueryWrapper<BizTask>().in(BizTask::getTaskNo, instanceIds));
            map = bizTasks.stream().collect(Collectors.toMap(BizTask::getTaskNo, BizTask::getStatus));
        }
        List<RuansiMissionTaskVo> objects = new ArrayList<>();
        for (ActHiProcinstVo instance : records) {
            String instanceId = instance.getId();
            ProcessProgressVo instanceProgress = processInstanceService.getInstanceProgress(null, instanceId);
            RuansiMissionTaskVo ruansiMissionTaskVo = getRuansiVo(instanceProgress, instance);
//            Map<String, Object> processInstanceFormData = businessDataService.getProcessInstanceFormData(instanceId);
//            RuansiMissionTaskVo ruansiMissionTaskVo = getRuansiVo(processInstanceFormData,instance);
            ruansiMissionTaskVo.setBizStatus(map.get(instanceId));
            objects.add(ruansiMissionTaskVo);
        }
        return objects;
    }

    private RuansiMissionTaskVo getRuansiVo(Map<String, Object> processInstanceFormData, ActHiProcinstVo instance) {
        RuansiMissionTaskVo ruansiMissionTaskVo = new RuansiMissionTaskVo();
        ruansiMissionTaskVo.setInstanceId(instance.getId());
        Map<String, Object> formData = processInstanceFormData;
        ruansiMissionTaskVo.setMissionTitle(String.valueOf(formData.get(WflowContants.NORMAL_MISSION_DEFAULT_TITLE_FIELD)));
        Object type = ((JSONArray) formData.get(WflowContants.NORMAL_MISSION_DEFAULT_TYPE_FIELD)).get(0);
        ruansiMissionTaskVo.setMissionTyle(String.valueOf(type));
        ruansiMissionTaskVo.setMissionLevel(String.valueOf(formData.get(WflowContants.NORMAL_MISSION_DEFAULT_LEVEL_FIELD)));
        ruansiMissionTaskVo.setStartTime(instance.getStartTime());
        String missionStatus = "RUNNING".equals(instance.getBusinessStatus()) ? "审批进行中" : "已完成";
        ruansiMissionTaskVo.setMissionStatus(missionStatus);
        OrgUser startUser = orgRepositoryService.getUsersBatchMap(Collections.singletonList(instance.getStartUserId())).get(instance.getStartUserId());
        ruansiMissionTaskVo.setStartUser(startUser);
        //判断是否可编辑，节点如果包含3个，说明已经被审批了，不可编辑；
//        boolean editable = CollectionUtil.isNotEmpty(instanceProgress.getProgress()) && instanceProgress.getProgress().size() <= 2;
        boolean editable = instanceCanEditable(instance.getId());
        ruansiMissionTaskVo.setEditable(editable);
        return ruansiMissionTaskVo;
    }

    /**
     * 判断是否可编辑
     *
     * @param instanceId
     * @return
     */
    private boolean instanceCanEditable(String instanceId) {
        Long count = actHiProcinstMapper.getHiTaskInstanceCountByInstanceId(instanceId);
        //确认是否含有被驳回的节点，如果有被驳回的节点，则可编辑
        return count <= 2;
    }

    private RuansiMissionTaskVo getRuansiVo(ProcessProgressVo instanceProgress, ActHiProcinstVo instance) {
        ProcessResultEnum processResult = ProcessResultEnum.resolveResult(instance.getEndActId());
        RuansiMissionTaskVo ruansiMissionTaskVo = new RuansiMissionTaskVo();
        ruansiMissionTaskVo.setInstanceId(instanceProgress.getInstanceId());
        Map<String, Object> formData = instanceProgress.getFormData();
        ruansiMissionTaskVo.setMissionTitle(String.valueOf(formData.get(WflowContants.NORMAL_MISSION_DEFAULT_TITLE_FIELD)));
        Object type = ((JSONArray) formData.get(WflowContants.NORMAL_MISSION_DEFAULT_TYPE_FIELD)).get(0);
        ruansiMissionTaskVo.setMissionTyle(String.valueOf(type));
        ruansiMissionTaskVo.setMissionLevel(String.valueOf(formData.get(WflowContants.NORMAL_MISSION_DEFAULT_LEVEL_FIELD)));
        ruansiMissionTaskVo.setStartTime(instanceProgress.getStartTime());
        ruansiMissionTaskVo.setMissionStatus(processResult.getDesc());
        ruansiMissionTaskVo.setStartUser(instanceProgress.getStaterUser());
        ruansiMissionTaskVo.setProcess(instanceProgress.getProgress());
        ruansiMissionTaskVo.setNodeId(instance.getProcDefKey());
        //判断是否可编辑，节点如果包含3个，说明已经被审批了，不可编辑；
       /* boolean editable = CollectionUtil.isNotEmpty(instanceProgress.getProgress()) && instanceProgress.getProgress().size() < 2;
        if (!editable) {
            editable = processResult == ProcessResultEnum.REFUSE;
        }*/
        ruansiMissionTaskVo.setEditable(canEditable(instanceProgress));
        return ruansiMissionTaskVo;
    }

    /**
     *  判断是否可编辑,如果最后一个progress是自己则可以编辑，则说明是被退回的状态
     *  如果第二个progress不是自己，并且是null，并且是审批节点时，说明是刚申请，还未审批状态，则可以编辑
     * @param instanceProgress
     * @return
     */
    private boolean canEditable(ProcessProgressVo instanceProgress) {
        boolean editable = false;
        List<ProcessProgressVo.ProgressNode> progress = instanceProgress.getProgress();
        if (progress.size() <= 1) {
            return true;
        }
        ProcessProgressVo.ProgressNode progressNode = progress.get(progress.size() - 1);
        ProcessHandlerParamsVo.Action result = progressNode.getResult();
        String nodeId = progressNode.getNodeId();
        if(nodeId.equals("root")){
            editable = true;
        }
        //如果第二个progress不是自己，并且是null，并且是审批节点时，说明是刚申请，还未审批状态，则可以编辑
        if (Objects.isNull(progress.get(1).getResult()) && progress.get(1).getNodeType() == NodeTypeEnum.APPROVAL) {
            editable = true;
        }
        return editable;
    }

    @Override
    public ProcessProgressVo getInstanceProgress(String nodeId, String instanceId) {
        //先查实例，然后判断是子流程还是主流程
        HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        //数据分类 表单配置及数据、审批任务结果、
        ProcessInstanceOwnerDto owner = null;
        Map<String, Object> formDatas = new HashMap<>();
        Map<String, ProcessHandlerParamsVo.Action> approvalResults = new HashMap<>();
        Map<String, Object> nodeProps = new HashMap<>();
        Map<String, String> signs = new HashMap<>();
        //是否是子流程
        boolean isSub = StrUtil.isNotBlank(instance.getSuperProcessInstanceId());
        HistoricProcessInstance mainInst = isSub ? null : instance;
        if (isSub) {
            //查出主流程表单数据
            mainInst = historyService.createHistoricProcessInstanceQuery().processInstanceId(instance.getSuperProcessInstanceId()).singleResult();
            formDatas = businessDataService.getProcessInstanceFormData(mainInst.getId());
        }
        //优化查询，把之前查好几次的一次性查出来然后再分类
        List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(instanceId).executionId(instanceId).list();
        Map<String, Object> vars = Objects.nonNull(instance.getEndTime()) ? new HashMap<>() : uelTools.getContextVar(instanceId, instance.getProcessDefinitionId());
        //遍历所有变量，将数据分类
        for (HistoricVariableInstance var : variables) {
            vars.put(var.getVariableName(), var.getValue());
            if (var.getVariableName().startsWith(WflowGlobalVarDef.TASK_RES_PRE)) {
                approvalResults.put(var.getVariableName(), (ProcessHandlerParamsVo.Action) var.getValue());
            } else if (!isSub && var.getVariableName().startsWith("field")) {
                formDatas.put(var.getVariableName(), var.getValue());
            } else if (var.getVariableName().startsWith("sign_")) {
                signs.put(var.getVariableName().substring(5), String.valueOf(var.getValue()));
            } else if (WflowGlobalVarDef.WFLOW_NODE_PROPS.equals(var.getVariableName())) {
                nodeProps = (Map<String, Object>) var.getValue();
            } else if (WflowGlobalVarDef.OWNER.equals(var.getVariableName())) {
                owner = (ProcessInstanceOwnerDto) var.getValue();
            } else if (WflowGlobalVarDef.START_DEPT.equals(var.getVariableName())) {
                String key = instance.getStartUserId() + "_" + var.getValue();
                Map<String, UserDeptDo> infoMap = orgRepositoryService.getUserDeptInfos(CollectionUtil.newArrayList(key));
                UserDeptDo userDeptDo = infoMap.getOrDefault(key, new UserDeptDo());
                owner = ProcessInstanceOwnerDto.builder().ownerDeptId(String.valueOf(var.getValue())).owner(instance.getStartUserId()).ownerName(userDeptDo.getUserName()).ownerDeptId(userDeptDo.getDeptId()).ownerDeptName(userDeptDo.getDeptName()).build();
            }
        }
        ProcessNode<?> currentNode = null;
        String modelFormConfig = null;
        ProcessProgressVo.InstanceExternSetting externSetting = null;
        OperationPerm operationPerms = null;
        Map<String, ProcessNode<?>> nodeMap = Collections.emptyMap();
        //搜索当前版本流程的配置
        WflowModelHistorys modelHistory = modelHistorysMapper.selectOne(new LambdaQueryWrapper<>(WflowModelHistorys.builder().processDefId(mainInst.getProcessDefinitionId()).version(mainInst.getProcessDefinitionVersion()).build()));
        List<Form> forms = JSONArray.parseArray(modelHistory.getFormItems(), Form.class);
        if (isSub) {
            WflowSubProcess subProcess = subProcessMapper.selectOne(new LambdaQueryWrapper<>(WflowSubProcess.builder().procDefId(instance.getProcessDefinitionId()).build()));
            nodeMap = nodeCatchService.reloadProcessByStr(subProcess.getProcess());
            currentNode = nodeMap.get(nodeId);
            operationPerms = getOperationPerm(currentNode);
            //获取主流程节点配置信息
            nodeProps = getNodeProps(nodeMap);
        }
        if (StrUtil.isNotBlank(nodeId)) {
            nodeMap = nodeCatchService.reloadProcessByStr(modelHistory.getProcess());
            currentNode = nodeMap.get(isSub ? instance.getBusinessKey() : nodeId);
            if (!isSub) {
                operationPerms = getOperationPerm(currentNode);
            }
            modelFormConfig = modelHistory.getFormConfig();
            externSetting = getExternSetting(modelHistory.getSettings(), instance.getStartUserId());
            nodeProps = getNodeProps(nodeMap);
        }
        if (Objects.isNull(nodeProps)) {
            nodeProps = getNodeProps(nodeCatchService.reloadProcessByStr(modelHistory.getProcess()));
        }
        //表单的 currentNode 以主流程为准
        List<Form> formItems = businessDataService.filterFormAndDataByPermConfig(forms, formDatas, currentNode);
        //下面都是一样的
        UserDo users = orgRepositoryService.getUserById(instance.getStartUserId());
        OrgUser startUser = OrgUser.builder().id(users.getUserId()).name(users.getUserName()).avatar(users.getAvatar()).build();
        List<ProcessProgressVo.ProgressNode> taskRecords = getHisTaskRecords(instanceId, nodeProps, approvalResults, signs, instance.getEndTime());
        //添加抄送
        taskRecords.addAll(getCcTaskRecords(instanceId));
        if (ObjectUtil.isNull(instance.getEndTime())) {
            taskRecords.addAll(processTaskService.getFutureTask(instance, owner.getOwnerDeptId(), vars, nodeMap));
        }
        //按开始时间对节点进行排序
        taskRecords = taskRecords.stream().sorted(Comparator.comparing(ProcessProgressVo.ProgressNode::getStartTime)).collect(Collectors.toList());
        ProcessProgressVo.ProgressNode progressNode = taskRecords.stream().filter(n -> "root".equals(n.getNodeId()) && Objects.isNull(n.getResult())).findFirst().orElse(null);
        if (Objects.nonNull(progressNode)) {
            //辅助前端UI构建，第一条一般都是
            progressNode.setResult(ProcessHandlerParamsVo.Action.complete);
            progressNode.setNodeType(NodeTypeEnum.ROOT);
        } else {
            //没有就进行构建，兼容之前的流程
            taskRecords.add(0, ProcessProgressVo.ProgressNode.builder().nodeId("root").name(isSub ? "发起子流程" : "提交申请").user(startUser).nodeType(NodeTypeEnum.ROOT).startTime(instance.getStartTime()).finishTime(instance.getStartTime()).taskId("root").result(ProcessHandlerParamsVo.Action.complete).build());
        }
        //提取全量表单数据
        if (StrUtil.isBlank(modelFormConfig)) {
            modelFormConfig = modelHistory.getFormConfig();
            externSetting = getExternSetting(modelHistory.getSettings(), instance.getStartUserId());
        }
        ProcessResultEnum processResult = ProcessResultEnum.resolveResult(instance.getEndActivityId());
        //获取BizTaskLog
        BizTaskLogBo bizTaskLogBo = new BizTaskLogBo();
        bizTaskLogBo.setTaskNo(instanceId);
        List<BizTaskLogVo> bizTaskLogVos = iBizTaskLogService.queryList(bizTaskLogBo);
        if (CollectionUtil.isEmpty(bizTaskLogVos)) {
            bizTaskLogVos = Collections.emptyList();
        }
        BizTask bizTask = bizTaskService.getStatus(instanceId);
        String bizStatus = "-1";
        Integer processPercent = 0;
        if (null != bizTask){
            bizStatus = bizTask.getStatus();
            processPercent = WflowContants.getPercentByStatus(bizStatus);
        }
        //获取群组id
        ImGroup imGroup = imGroupMapper.selectByTaskNo(instanceId);
        boolean isInGroup = checkInGroup(imGroup);
        Long groupId = null;
        if (isInGroup) {
            groupId = imGroup.getId();
        }
        return ProcessProgressVo.builder().instanceId(instanceId).version(instance.getProcessDefinitionVersion()).formItems(formItems).formConfig(JSONObject.parseObject(modelFormConfig)).formData(formDatas).processDefName(instance.getProcessDefinitionName()).staterUser(startUser).starterDept(null == owner ? null : owner.getOwnerDeptName()).status(processResult.getDesc()).result(processResult).startTime(instance.getStartTime()).finishTime(instance.getEndTime()).progress(taskRecords).operationPerm(operationPerms).externSetting(externSetting).taskLogVos(bizTaskLogVos).bizStatus(bizStatus).bizTask(bizTask).processPercent(processPercent).groupId(groupId).build();
    }

    private boolean checkInGroup(ImGroup imGroup) {
        if (null == imGroup) {
            return false;
        }
        Long userId = LoginHelper.getUserId();
        int count = imGroupMemberMapper.checkInGroup(userId, imGroup.getId());
        return count > 0;
    }

    @Override
    public ProcessProgressVo getInstanceProgressApp(String instanceId, String nodeId) {
        //先查实例，然后判断是子流程还是主流程
        HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        //数据分类 表单配置及数据、审批任务结果、
        ProcessInstanceOwnerDto owner = null;
        Map<String, Object> formDatas = new HashMap<>();
        Map<String, ProcessHandlerParamsVo.Action> approvalResults = new HashMap<>();
        Map<String, Object> nodeProps = new HashMap<>();
        Map<String, String> signs = new HashMap<>();
        //是否是子流程
        boolean isSub = StrUtil.isNotBlank(instance.getSuperProcessInstanceId());
        HistoricProcessInstance mainInst = isSub ? null : instance;
        if (isSub) {
            //查出主流程表单数据
            mainInst = historyService.createHistoricProcessInstanceQuery().processInstanceId(instance.getSuperProcessInstanceId()).singleResult();
            formDatas = businessDataService.getProcessInstanceFormData(mainInst.getId());
        }
        //优化查询，把之前查好几次的一次性查出来然后再分类
        List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(instanceId).executionId(instanceId).list();
        Map<String, Object> vars = Objects.nonNull(instance.getEndTime()) ? new HashMap<>() : uelTools.getContextVar(instanceId, instance.getProcessDefinitionId());
        //遍历所有变量，将数据分类
        for (HistoricVariableInstance var : variables) {
            vars.put(var.getVariableName(), var.getValue());
            if (var.getVariableName().startsWith(WflowGlobalVarDef.TASK_RES_PRE)) {
                approvalResults.put(var.getVariableName(), (ProcessHandlerParamsVo.Action) var.getValue());
            } else if (!isSub && var.getVariableName().startsWith("field")) {
                formDatas.put(var.getVariableName(), var.getValue());
            } else if (var.getVariableName().startsWith("sign_")) {
                signs.put(var.getVariableName().substring(5), String.valueOf(var.getValue()));
            } else if (WflowGlobalVarDef.WFLOW_NODE_PROPS.equals(var.getVariableName())) {
                nodeProps = (Map<String, Object>) var.getValue();
            } else if (WflowGlobalVarDef.OWNER.equals(var.getVariableName())) {
                owner = (ProcessInstanceOwnerDto) var.getValue();
            } else if (WflowGlobalVarDef.START_DEPT.equals(var.getVariableName())) {
                String key = instance.getStartUserId() + "_" + var.getValue();
                Map<String, UserDeptDo> infoMap = orgRepositoryService.getUserDeptInfos(CollectionUtil.newArrayList(key));
                UserDeptDo userDeptDo = infoMap.getOrDefault(key, new UserDeptDo());
                owner = ProcessInstanceOwnerDto.builder().ownerDeptId(String.valueOf(var.getValue())).owner(instance.getStartUserId()).ownerName(userDeptDo.getUserName()).ownerDeptId(userDeptDo.getDeptId()).ownerDeptName(userDeptDo.getDeptName()).build();
            }
        }
        ProcessNode<?> currentNode = null;
        String modelFormConfig = null;
        ProcessProgressVo.InstanceExternSetting externSetting = null;
        OperationPerm operationPerms = null;
        Map<String, ProcessNode<?>> nodeMap = Collections.emptyMap();
        //搜索当前版本流程的配置
        WflowModelHistorys modelHistory = modelHistorysMapper.selectOne(new LambdaQueryWrapper<>(WflowModelHistorys.builder().processDefId(mainInst.getProcessDefinitionId()).version(mainInst.getProcessDefinitionVersion()).build()));
        List<Form> forms = JSONArray.parseArray(modelHistory.getFormItems(), Form.class);
        if (isSub) {
            WflowSubProcess subProcess = subProcessMapper.selectOne(new LambdaQueryWrapper<>(WflowSubProcess.builder().procDefId(instance.getProcessDefinitionId()).build()));
            nodeMap = nodeCatchService.reloadProcessByStr(subProcess.getProcess());
            currentNode = nodeMap.get(nodeId);
            operationPerms = getOperationPerm(currentNode);
            //获取主流程节点配置信息
            nodeProps = getNodeProps(nodeMap);
        }
        if (StrUtil.isNotBlank(nodeId)) {
            nodeMap = nodeCatchService.reloadProcessByStr(modelHistory.getProcess());
            currentNode = nodeMap.get(isSub ? instance.getBusinessKey() : nodeId);
            if (!isSub) {
                operationPerms = getOperationPerm(currentNode);
            }
            modelFormConfig = modelHistory.getFormConfig();
            externSetting = getExternSetting(modelHistory.getSettings(), instance.getStartUserId());
            nodeProps = getNodeProps(nodeMap);
        }
        if (Objects.isNull(nodeProps)) {
            nodeProps = getNodeProps(nodeCatchService.reloadProcessByStr(modelHistory.getProcess()));
        }
        //表单的 currentNode 以主流程为准
        List<Form> formItems = businessDataService.filterFormAndDataByPermConfig(forms, formDatas, currentNode);
        //下面都是一样的
        UserDo users = orgRepositoryService.getUserById(instance.getStartUserId());
        OrgUser startUser = OrgUser.builder().id(users.getUserId()).name(users.getUserName()).avatar(users.getAvatar()).build();
        List<ProcessProgressVo.ProgressNode> taskRecords = getHisTaskRecords(instanceId, nodeProps, approvalResults, signs, instance.getEndTime());
        //添加抄送
        taskRecords.addAll(getCcTaskRecords(instanceId));
        if (ObjectUtil.isNull(instance.getEndTime())) {
            taskRecords.addAll(processTaskService.getFutureTask(instance, owner.getOwnerDeptId(), vars, nodeMap));
        }
        //按开始时间对节点进行排序
        taskRecords = taskRecords.stream().sorted(Comparator.comparing(ProcessProgressVo.ProgressNode::getStartTime)).collect(Collectors.toList());
        ProcessProgressVo.ProgressNode progressNode = taskRecords.stream().filter(n -> "root".equals(n.getNodeId()) && Objects.isNull(n.getResult())).findFirst().orElse(null);
        if (Objects.nonNull(progressNode)) {
            //辅助前端UI构建，第一条一般都是
            progressNode.setResult(ProcessHandlerParamsVo.Action.complete);
            progressNode.setNodeType(NodeTypeEnum.ROOT);
        } else {
            //没有就进行构建，兼容之前的流程
            taskRecords.add(0, ProcessProgressVo.ProgressNode.builder().nodeId("root").name(isSub ? "发起子流程" : "提交申请").user(startUser).nodeType(NodeTypeEnum.ROOT).startTime(instance.getStartTime()).finishTime(instance.getStartTime()).taskId("root").result(ProcessHandlerParamsVo.Action.complete).build());
        }
        //提取全量表单数据
        if (StrUtil.isBlank(modelFormConfig)) {
            modelFormConfig = modelHistory.getFormConfig();
            externSetting = getExternSetting(modelHistory.getSettings(), instance.getStartUserId());
        }
        ProcessResultEnum processResult = ProcessResultEnum.resolveResult(instance.getEndActivityId());
        //获取BizTaskLog
        BizTaskLogBo bizTaskLogBo = new BizTaskLogBo();
        bizTaskLogBo.setTaskNo(instanceId);
        List<BizTaskLogVo> bizTaskLogVos = iBizTaskLogService.queryList(bizTaskLogBo);
        if (CollectionUtil.isEmpty(bizTaskLogVos)) {
            bizTaskLogVos = Collections.emptyList();
        }
        BizTask bizTask = bizTaskService.getStatus(instanceId);
        String bizStatus = "-1";
        Integer processPercent = 0;
        if (null != bizTask){
            bizStatus = bizTask.getStatus();
            processPercent = WflowContants.getPercentByStatus(bizStatus);
        }

        List<Form> newFormItems = new ArrayList<>();
        flattenAndFilter(formItems, newFormItems);
        //获取群组id
        ImGroup imGroup = imGroupMapper.selectByTaskNo(instanceId);
        boolean isInGroup = checkInGroup(imGroup);
        Long groupId = null;
        if (isInGroup) {
            groupId = imGroup.getId();
        }
        ProcessProgressVo processProgressVo = ProcessProgressVo.builder().instanceId(instanceId).version(instance.getProcessDefinitionVersion()).formItems(newFormItems).formConfig(JSONObject.parseObject(modelFormConfig)).formData(formDatas).processDefName(instance.getProcessDefinitionName()).staterUser(startUser).starterDept(null == owner ? null : owner.getOwnerDeptName()).status(processResult.getDesc()).result(processResult).startTime(instance.getStartTime()).finishTime(instance.getEndTime()).progress(taskRecords).operationPerm(operationPerms).externSetting(externSetting).taskLogVos(bizTaskLogVos).bizStatus(bizStatus).bizTask(bizTask).processPercent(processPercent).groupId(groupId).build();
        processProgressVo.setBizTaskWorkList(bizTaskWorkMapper.selectByTaskNo(instanceId));
        return processProgressVo;
    }

    public void flattenAndFilter(List<Form> forms, List<Form> newForms) {
        forms.forEach(form -> {
            Map<String, Object> props = form.getProps();
            List<Form> items = (List<Form>) props.get("items");
            if (Objects.nonNull(items)) {
                flattenAndFilter(items, newForms);
            } else {
                newForms.add(form);
            }
        });
    }

    @Override
    public BizTask getInstanceProgressApp(String instanceId) {
        BizTask bizTask = bizTaskMapper.selectByTaskNo(instanceId);
        bizTask.setJsonImage(JSONArray.parseArray(bizTask.getImage()));
        bizTask.setJsonFile(JSONArray.parseArray(bizTask.getFile()));
        List<BizTaskLog> bizTaskLogList = bizTaskLogMapper.selectByTaskNo(instanceId);
        bizTask.setBizTaskLogList(bizTaskLogList);
        return bizTask;
    }

    /**
     * 1.修改wflow_form_data的数据
     * 2.修改act_hi_varinst的数据
     */
    @Transactional
    @Override
    public Boolean editProcess(ProcessStartParamsVo params) {
        Long userId = LoginHelper.getUserId();
        String instanceId = params.getInstanceId();
        List<WflowFormRecord> wflowFormRecords = businessDataService.updateInstanceFormData(String.valueOf(userId), instanceId, params.getFormData());
        bizTaskService.updateInstanceFormData(instanceId, params.getFormData());
        return !wflowFormRecords.isEmpty();
    }

    @Transactional
    public void saveBizTaskLog(String instanceId) {
        BizTaskBo bizTaskBo = new BizTaskBo();
        bizTaskBo.setTaskNo(instanceId);
        iBizTaskLogService.saveToBizTaskLog(instanceId, String.valueOf(LoginHelper.getUserId()), WflowContants.BIZ_TASK_STATUS_START, "修改后重新提交", null, null);
    }

    /**
     * 获取流程处理操作权限
     *
     * @param currentNode 当前的节点
     * @return 操作权限设置
     */
    private OperationPerm getOperationPerm(ProcessNode<?> currentNode) {
        OperationPerm operationPerm = null;
        if (Objects.nonNull(currentNode)) {
            if (NodeTypeEnum.ROOT.equals(currentNode.getType())) {
                RootProps props = (RootProps) currentNode.getProps();
                operationPerm = props.getOperationPerm();
                if (Objects.isNull(operationPerm)) {
                    operationPerm = OperationPerm.builder().complete(new OperationPerm.Operations("提交", true)).build();
                } else {
                    OperationPerm.Operations agree = operationPerm.getAgree();
                    if (Objects.nonNull(agree) && Objects.isNull(operationPerm.getComplete())) {
                        agree.setAlisa("提交");
                        operationPerm.setComplete(agree);
                    }
                    operationPerm.setAgree(null);
                }
            } else if (NodeTypeEnum.APPROVAL.equals(currentNode.getType())) {
                ApprovalProps props = (ApprovalProps) currentNode.getProps();
                operationPerm = props.getOperationPerm();
                if (Objects.isNull(operationPerm)) {
                    operationPerm = OperationPerm.builder().agree(new OperationPerm.Operations("同意", true)).refuse(new OperationPerm.Operations("拒绝", true)).transfer(new OperationPerm.Operations("转交", true)).afterAdd(new OperationPerm.Operations("加签", true)).recall(new OperationPerm.Operations("退回", true)).build();
                }
            } else if (NodeTypeEnum.TASK.equals(currentNode.getType())) {
                ApprovalProps props = (ApprovalProps) currentNode.getProps();
                operationPerm = props.getOperationPerm();
                if (Objects.isNull(operationPerm)) {
                    operationPerm = OperationPerm.builder().complete(new OperationPerm.Operations("提交", true)).transfer(new OperationPerm.Operations("转办", true)).afterAdd(new OperationPerm.Operations("加签", true)).recall(new OperationPerm.Operations("退回", true)).build();
                } else {
                    OperationPerm.Operations agree = operationPerm.getAgree();
                    if (Objects.nonNull(agree) && Objects.isNull(operationPerm.getComplete())) {
                        agree.setAlisa("提交");
                        operationPerm.setComplete(agree);
                    }
                    operationPerm.setAgree(null);
                }
            }
        }
        return operationPerm;
    }

    private ProcessProgressVo.InstanceExternSetting getExternSetting(String setting, String startUser) {
        JSONObject parsed = JSONObject.parseObject(setting);
        return ProcessProgressVo.InstanceExternSetting.builder().enableSign(parsed.getBoolean("sign")).enableCancel(Boolean.TRUE.equals(parsed.getBoolean("enableCancel")) && startUser.equals(UserUtil.getLoginUserId())).build();
    }

    private Map<String, Object> getNodeProps(Map<String, ProcessNode<?>> nodeMap) {
        return nodeMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, v -> null == v.getValue().getProps() ? new HashMap<>() : v.getValue().getProps()));
    }

    /**
     * 获取流程的审批历史记录
     *
     * @param instanceId  审批实例ID
     * @param nodeProps   节点设置
     * @param varMap      变量
     * @param signs       签名
     * @param instEndTime 流程实例结束时间
     * @return 历史记录列表
     */
    private List<ProcessProgressVo.ProgressNode> getHisTaskRecords(String instanceId, Map<String, Object> nodeProps, Map<String, ProcessHandlerParamsVo.Action> varMap, Map<String, String> signs, Date instEndTime) {
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().processInstanceId(instanceId).orderByHistoricActivityInstanceStartTime().asc().list();
        Set<String> userSet = new HashSet<>();
        //获取节点处理结果
        Map<String, List<TaskCommentVo>> commentMap = new HashMap<>();
        //统一处理所有评论数据，省的多次查询
        List<TaskCommentVo> cmvos = taskService.getProcessInstanceComments(instanceId).stream().map(comment -> {
            userSet.add(comment.getUserId());
            TaskCommentVo commentVo = TaskCommentVo.builder().id(comment.getId()).taskId(comment.getTaskId()).commentType(comment.getType()).type("COMMENT").createTime(comment.getTime()).user(OrgUser.builder().id(comment.getUserId()).build()).build();
            ProcessHandlerParamsVo.ProcessComment processComment = JSONObject.parseObject(comment.getFullMessage(), ProcessHandlerParamsVo.ProcessComment.class);
            commentVo.setText(processComment.getText());
            commentVo.setAttachments(processComment.getAttachments());
            return commentVo;
        }).toList();
        cmvos.forEach(cm -> {
            //把评论数据按照task进行归类
            String taskId = Optional.ofNullable(cm.getTaskId()).orElse(instanceId);
            List<TaskCommentVo> vos = commentMap.computeIfAbsent(taskId, k -> new ArrayList<>());
            vos.add(cm);
        });
        List<ProcessProgressVo.ProgressNode> progressNodes = list.stream().filter(his -> ObjectUtil.isNotNull(his.getTaskId()) || "callActivity".equals(his.getActivityType())).map(his -> {
            Object props = nodeProps.get(his.getActivityId());
            List<TaskCommentVo> commentVos = commentMap.getOrDefault(his.getTaskId(), Collections.emptyList());
            ProcessProgressVo.ProgressNode node = ProcessProgressVo.ProgressNode.builder().nodeId(his.getActivityId()).isFuture(false).name(his.getActivityName()).startTime(his.getStartTime()).finishTime(Optional.ofNullable(his.getEndTime()).orElse(instEndTime)).comment(commentVos).build();
            if ("callActivity".equals(his.getActivityType())) {
                node.setNodeType(NodeTypeEnum.SUBPROC);
                //取子流程实例
                HistoricProcessInstance subInst = historyService.createHistoricProcessInstanceQuery().processInstanceId(his.getCalledProcessInstanceId()).singleResult();
                userSet.add(subInst.getStartUserId());
                node.setUser(OrgUser.builder().id(subInst.getStartUserId()).build());
                node.setTaskId(subInst.getId());
                ProcessResultEnum result = ProcessResultEnum.resolveResult(subInst.getEndActivityId());
                switch (result) {
                    case PASS:
                        node.setResult(ProcessHandlerParamsVo.Action.agree);
                        break;
                    case REFUSE:
                        node.setResult(ProcessHandlerParamsVo.Action.refuse);
                        break;
                    case CANCEL:
                        node.setResult(ProcessHandlerParamsVo.Action.cancel);
                        break;
                }
            } else {
                ApprovalModeEnum approvalMode = null;
                if (props instanceof ApprovalProps) {
                    approvalMode = ((ApprovalProps) props).getMode();
                }
                userSet.add(his.getAssignee());
                node.setNodeType(NodeTypeEnum.APPROVAL);
                node.setApprovalMode(approvalMode);
                node.setUser(OrgUser.builder().id(his.getAssignee()).build());
                node.setTaskId(his.getTaskId());
                node.setSignature(signs.get(his.getTaskId()));
                node.setResult(varMap.get(WflowGlobalVarDef.TASK_RES_PRE + his.getTaskId()));
            }
            return node;
        }).collect(Collectors.toList());
        //将非任务类的评论转换成流程节点
        progressNodes.addAll(commentMap.getOrDefault(instanceId, Collections.emptyList()).stream().map(cm -> ProcessProgressVo.ProgressNode.builder().nodeId(cm.getId()).name("参与评论").user(cm.getUser()).startTime(cm.getCreateTime()).finishTime(cm.getCreateTime()).taskId(cm.getId()).comment(CollectionUtil.newArrayList(cm)).result(ProcessHandlerParamsVo.Action.comment).build()).collect(Collectors.toList()));
        if (CollectionUtil.isNotEmpty(userSet)) {
            //过滤掉系统节点
            Map<String, OrgUser> map = userDeptOrLeaderService.getUserMapByIds(userSet.stream().filter(v -> !WflowGlobalVarDef.WFLOW_TASK_AGRRE.equals(v) && !WflowGlobalVarDef.WFLOW_TASK_REFUSE.equals(v)).collect(Collectors.toSet()));
            progressNodes.forEach(n -> {
                if (WflowGlobalVarDef.WFLOW_TASK_AGRRE.equals(n.getUser().getId()) || WflowGlobalVarDef.WFLOW_TASK_REFUSE.equals(n.getUser().getId())) {
                    n.setUser(WflowGlobalVarDef.SYS);
                } else {
                    n.setUser(map.get(n.getUser().getId()));
                    n.getComment().forEach(c -> c.setUser(map.get(c.getUser().getId())));
                }
            });
        }
        return progressNodes;
    }

    /**
     * 获取抄送的流程实例信息
     *
     * @param instanceId 实例ID
     * @return 抄送我的流程
     */
    private List<ProcessProgressVo.ProgressNode> getCcTaskRecords(String instanceId) {
        Set<String> ccUsers = new HashSet<>();
        List<ProcessProgressVo.ProgressNode> ccList = ccTasksMapper.selectList(new LambdaQueryWrapper<WflowCcTasks>().eq(WflowCcTasks::getInstanceId, instanceId)).stream().map(task -> {
            ccUsers.add(task.getUserId());
            return ProcessProgressVo.ProgressNode.builder().nodeId(task.getNodeId()).nodeType(NodeTypeEnum.CC).isFuture(false).name(task.getNodeName()).comment(Collections.emptyList()).user(OrgUser.builder().id(task.getUserId()).build()).startTime(task.getCreateTime()).finishTime(task.getCreateTime()).build();
        }).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(ccUsers)) {
            Map<String, OrgUser> userMap = userDeptOrLeaderService.getUserMapByIds(ccUsers);
            ccList.stream().peek(v -> v.setUser(userMap.get(v.getUser().getId()))).toList();
        }
        return ccList;
    }


}
