package com.codvision.workflow.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.codvision.auth.entity.vo.SysUserVO;
import com.codvision.auth.entity.vo.UserAssociatedInfoVO;
import com.codvision.auth.mapper.SysUserMapper;
import com.codvision.auth.service.third.GovDingService;
import com.codvision.auth.support.UserContext;
import com.codvision.base.entity.dto.SysNoticeDTO;
import com.codvision.base.service.ISysNoticeService;
import com.codvision.cachecore.utils.RedisUtil;
import com.codvision.commoncore.exception.BusinessException;
import com.codvision.commoncore.utils.Preconditions;
import com.codvision.workflow.config.WorkFlowServiceFactory;
import com.codvision.workflow.constant.enums.WorkFlowUrgingTypeEnum;
import com.codvision.workflow.entity.*;
import com.codvision.workflow.entity.dto.WorkFlowDynamicAllocationDTO;
import com.codvision.workflow.entity.dto.WorkFlowTaskHandleDTO;
import com.codvision.workflow.entity.dto.WorkFlowTaskReturnLimitDTO;
import com.codvision.workflow.mapper.WorkFlowMapper;
import com.codvision.workflow.util.WorkFlowUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.*;
import org.flowable.common.engine.api.FlowableTaskAlreadyClaimedException;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.util.ExecutionGraphUtil;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static com.codvision.workflow.constant.CacheContant.*;
import static com.codvision.workflow.constant.WorkFlowConstant.*;
import static com.codvision.workflow.constant.enums.WorkFlowOperationTypeEnum.*;

/**
 * @author hxl
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WorkFlowTaskService extends WorkFlowServiceFactory {

    private final ISysNoticeService sysNoticeService;
    private final WorkFlowRecordService recordService;
    private final WorkFlowMapper workFlowMapper;
    private final WorkFlowButtonService workFlowButtonService;
    private final WorkFlowDataService workFlowDataService;
    private final WorkFlowService workFlowService;
    private final SysUserMapper sysUserMapper;
    private final GovDingService govDingService;
    private final WorkFlowSubDataService workFlowSubDataService;
    private final WorkFlowCcItemService workFlowCcItemService;

    private List<String> getCurrentOrgIdList(SysUserVO sysUserVO) {
        return sysUserVO.getAssociatedInfos().stream().map(UserAssociatedInfoVO::getOid).map(String::valueOf).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public void complete(WorkFlowTaskHandleDTO taskHandleDTO) {
        SysUserVO currentSysUser = UserContext.get();
        Task task = taskService.createTaskQuery().taskId(taskHandleDTO.getTaskId())
                .or()
                .taskCandidateOrAssigned(currentSysUser.getId().toString())
                .taskCandidateGroupIn(getCurrentOrgIdList(currentSysUser))
                .endOr()
                .singleResult();
        Preconditions.checkArgument(task != null,"获取任务信息失败");

        String jsonData = null;
        if (ObjectUtil.isNotEmpty(taskHandleDTO.getVariables())) {
            workFlowService.initDefaultVariables(taskHandleDTO.getVariables());
            taskService.setVariables(task.getId(), taskHandleDTO.getVariables());
            jsonData = JSONUtil.toJsonStr(taskHandleDTO.getVariables());
            Boolean isSubData = (Boolean) taskService.getVariableLocal(task.getId(), SUB_DATA);
            if (isSubData != null && isSubData) {
                WorkFlowSubData workFlowSubData = workFlowSubDataService.getByTaskId(task.getId());
                if (workFlowSubData == null) {
                    workFlowSubData = WorkFlowSubData.builder()
                            .instanceId(task.getProcessInstanceId()).taskId(task.getId()).taskKey(task.getTaskDefinitionKey())
                            .operatorUid(currentSysUser.getId()).operatorName(currentSysUser.getName()).operatorOid(currentSysUser.getActiveOid())
                            .formDataJson(jsonData)
                            .build();
                    workFlowSubDataService.save(workFlowSubData);
                } else {
                    workFlowSubDataService.updateFormData(task.getId(), jsonData);
                }
            } else {
                workFlowDataService.updateFormDataByInstanceId(task.getProcessInstanceId(), jsonData);
            }
        }

        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            // 办理委派任务
            taskService.resolveTask(taskHandleDTO.getTaskId());
        } else {
            if (taskHandleDTO.getAllocation() != null) {
                dynamicAllocation(taskHandleDTO.getAllocation());
            }

            BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
            // 判断当前是否为多实例节点
            if (WorkFlowUtil.isParallelMultiInstance(bpmnModel, task.getTaskDefinitionKey())) {
                Set<String> cacheSet = new HashSet<>();
                cacheSet.add(task.getId());
                String key = WORK_FLOW_MULTI_INSTANCE_COMPLETED + task.getTaskDefinitionKey();
                if (RedisUtil.hasKey(key)) {
                    cacheSet.addAll(RedisUtil.get(key));
                }

                RedisUtil.set(key, cacheSet);
            }
            taskService.setAssignee(taskHandleDTO.getTaskId(), currentSysUser.getId().toString());
            taskService.complete(taskHandleDTO.getTaskId());
        }
        // 抄送用户
        WorkFlowCcItem ccItem = WorkFlowCcItem.builder().definitionId(task.getProcessDefinitionId()).instanceId(task.getProcessInstanceId()).taskId(task.getId()).taskName(task.getName())
                .ccUid(currentSysUser.getId()).ccName(currentSysUser.getName()).build();
        workFlowCcItemService.addCcItem(ccItem, taskHandleDTO.getToCcUserIds());
        // 设置流程状态
        setFlowStatus(AGREED.getCode(), task.getProcessInstanceId());
        // 添加操作记录
        recordService.addTaskRecord(taskHandleDTO.getTaskId(), AGREED.getType(), taskHandleDTO.getComment(), jsonData);
    }

    @Transactional(rollbackFor = Exception.class)
    public void reject(WorkFlowTaskHandleDTO taskHandleDTO) {
        SysUserVO currentSysUser = UserContext.get();
        Task task = taskService.createTaskQuery().taskId(taskHandleDTO.getTaskId())
                .or()
                .taskCandidateOrAssigned(currentSysUser.getId().toString())
                .taskCandidateGroupIn(getCurrentOrgIdList(currentSysUser))
                .endOr()
                .singleResult();
        Preconditions.checkArgument(task != null,"获取任务信息失败");

        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            // 办理委派任务
            taskService.resolveTask(taskHandleDTO.getTaskId());
        } else {
            // 获取结束事件
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
            EndEvent endEvent = WorkFlowUtil.getEndEvent(bpmnModel);
            // 跳转至结束事件
            List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();
            List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
            runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId()).moveExecutionsToSingleActivityId(executionIds, endEvent.getId()).changeState();
        }

        if (ObjectUtil.isNotEmpty(taskHandleDTO.getVariables())) {
            workFlowService.initDefaultVariables(taskHandleDTO.getVariables());
            workFlowDataService.updateFormDataByInstanceId(task.getProcessInstanceId(), JSONUtil.toJsonStr(taskHandleDTO.getVariables()));
        }

        // 抄送用户
        WorkFlowCcItem ccItem = WorkFlowCcItem.builder().definitionId(task.getProcessDefinitionId()).instanceId(task.getProcessInstanceId()).taskId(task.getId()).taskName(task.getName())
                .ccUid(currentSysUser.getId()).ccName(currentSysUser.getName()).build();
        workFlowCcItemService.addCcItem(ccItem, taskHandleDTO.getToCcUserIds());
        // 设置流程状态
        setFlowStatus(REJECTED.getCode(), task.getProcessInstanceId());
        // 添加操作记录
        recordService.addTaskRecord(taskHandleDTO.getTaskId(), REJECTED.getType(), taskHandleDTO.getComment(), null);
    }


    public void cancel(String instanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).active().singleResult();
        Preconditions.checkArgument(processInstance != null,"流程已结束或已挂起，无法执行撤销操作");

        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceId).finished().list();
        Preconditions.checkArgument(CollectionUtils.isEmpty(historicTaskInstances),"流程已有用户已办理，无法执行撤销操作");

        // 获取结束事件
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        EndEvent endEvent = WorkFlowUtil.getEndEvent(bpmnModel);
        // 跳转至结束事件
        List<Execution> executions = runtimeService.createExecutionQuery().parentId(instanceId).list();
        List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
        runtimeService.createChangeActivityStateBuilder().processInstanceId(instanceId).moveExecutionsToSingleActivityId(executionIds, endEvent.getId()).changeState();
    }

    @Transactional(rollbackFor = Exception.class)
    public void taskReturn(WorkFlowTaskHandleDTO taskHandleDTO) {
        SysUserVO currentSysUser = UserContext.get();
        Task task = taskService.createTaskQuery().taskId(taskHandleDTO.getTaskId())
                .or().taskCandidateOrAssigned(currentSysUser.getId().toString()).taskCandidateGroupIn(getCurrentOrgIdList(currentSysUser)).endOr().singleResult();
        Preconditions.checkArgument(task != null,"获取任务信息失败");
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).active().singleResult();
        Preconditions.checkArgument(processInstance != null,"流程已结束或已挂起，无法进行退回操作");

        // 获取流程模型信息
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        // 判断回退次数是否已达到上限
        checkTaskReturn(currentSysUser, task);
        // 判断当前节点是否在并行或包容网关内，若在，则检查其他节点是否已处置完毕，若是则不支持退回。并获取网关的所有节点信息
        List<String> gatewayUserTaskKeys = checkGatewayCondition(bpmnModel, task);
        gatewayUserTaskKeys.remove(task.getTaskDefinitionKey());

        // 获取当前任务节点元素
        FlowElement source = WorkFlowUtil.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
        Preconditions.checkArgument(source != null, "获取当前任务节点信息失败");
        if (StringUtils.isBlank(taskHandleDTO.getTargetTaskKey())) {
            // 默认优先使用退回配置，若无配置则默认退回至上一步操作
            taskHandleDTO.setTargetTaskKey(getReturnTargetKey(source, task));
        }

        // 获取目标节点元素
        FlowElement target = WorkFlowUtil.getFlowElementById(bpmnModel, taskHandleDTO.getTargetTaskKey());
        Preconditions.checkArgument(target != null, "获取目标节点信息失败");
        // 判断是否可达
        boolean isSequential = ExecutionGraphUtil.isReachable(bpmnModel.getMainProcess(), (FlowNode) target, (FlowNode) source, new HashSet<>());
        Preconditions.checkArgument(isSequential, "目标节点对于当前节点不可达，请重新选择目标节点");

        // 获取所有正常进行的任务节点 Key，这些任务不能直接使用，需要找出其中需要撤回的任务
        List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
        List<String> runTaskKeyList = new ArrayList<>();
        runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
        // 需退回任务列表
        List<String> currentIds = new ArrayList<>();
        // 通过父级网关的出口连线，结合 runTaskList 比对，获取需要撤回的任务
        List<UserTask> currentUserTaskList = WorkFlowUtil.iteratorFindChildUserTasks(target, runTaskKeyList, null, null);
        currentUserTaskList.forEach(item -> currentIds.add(item.getId()));

        String currentTime = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN);
        // 更新当前任务操作记录信息
        recordService.updateCurrentTaskRecord(task.getId(), RETURN.getType(),  taskHandleDTO.getComment(), currentTime);
        // 清除多余记录
        for (String key : gatewayUserTaskKeys) {
            WorkFlowRecord workFlowRecord = recordService.getLatestByInstanceIdAndActivityId(task.getProcessInstanceId(), key);
            if (workFlowRecord != null) {
                recordService.removeById(workFlowRecord.getId());
            }
        }

        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(task.getProcessInstanceId())
                .moveActivityIdsToSingleActivityId(currentIds, target.getId()).changeState();
        recordService.addReturnRecord(task.getProcessInstanceId(), target.getId(), currentTime);
    }

    @Transactional(rollbackFor = Exception.class)
    public void revokeRedo(WorkFlowTaskHandleDTO taskHandleDTO) {
        SysUserVO sysUserVO = UserContext.get();
        HistoricTaskInstance currTaskIns = historyService.createHistoricTaskInstanceQuery().taskId(taskHandleDTO.getTaskId()).taskAssignee(sysUserVO.getId().toString()).singleResult();
        Preconditions.checkArgument(currTaskIns != null,"获取任务信息失败");

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(currTaskIns.getProcessInstanceId()).active().singleResult();
        Preconditions.checkArgument(processInstance != null,"流程已结束或已挂起，无法执行撤回操作");

        // 获取bpmn模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(currTaskIns.getProcessDefinitionId());
        UserTask currUserTask = WorkFlowUtil.getUserTaskByKey(bpmnModel, currTaskIns.getTaskDefinitionKey());
        // 查找下一级用户任务列表
        List<UserTask> nextUserTaskList = WorkFlowUtil.findNextUserTasks(currUserTask);
        List<String> nextUserTaskKeys = nextUserTaskList.stream().map(UserTask::getId).collect(Collectors.toList());

        // 获取当前节点之后已完成的流程历史节点
        List<HistoricTaskInstance> finishedTaskInsList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(currTaskIns.getProcessInstanceId())
                .taskCreatedAfter(currTaskIns.getEndTime())
                .finished()
                .list();
        for (HistoricTaskInstance finishedTaskInstance : finishedTaskInsList) {
            // 检查已完成流程历史节点是否存在下一级中
            if (CollUtil.contains(nextUserTaskKeys, finishedTaskInstance.getTaskDefinitionKey())) {
                throw new BusinessException("下一个流程已被处理，无法执行撤回操作");
            }
        }

        // 获取所有激活的任务节点，找到需要撤回的任务
        List<Task> activateTaskList = taskService.createTaskQuery().processInstanceId(currTaskIns.getProcessInstanceId()).list();
        List<String> revokeExecutionIds = new ArrayList<>();
        List<String> taskIdList = new ArrayList<>();
        for (Task task : activateTaskList) {
            // 检查激活的任务节点是否存在下一级中，如果存在，则加入到需要撤回的节点
            if (CollUtil.contains(nextUserTaskKeys, task.getTaskDefinitionKey())) {
                revokeExecutionIds.add(task.getExecutionId());
                taskIdList.add(task.getId());
            }
        }

        if (CollectionUtils.isEmpty(revokeExecutionIds)) {
            throw new BusinessException("当前无法执行撤回操作");
        }

        // 跳转至当前节点
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(currTaskIns.getProcessInstanceId())
                .moveExecutionsToSingleActivityId(revokeExecutionIds, currTaskIns.getTaskDefinitionKey()).changeState();

        // 清除历史数据
        String startTime = DateUtil.format(currTaskIns.getCreateTime(), DatePattern.NORM_DATETIME_MS_PATTERN);
        workFlowMapper.delHistoricActivityInstance(currTaskIns.getExecutionId(), startTime);
        for (String taskId : taskIdList) {
            recordService.delByTaskId(taskId);
            historyService.deleteHistoricTaskInstance(taskId);
        }

        // 设置流程状态
        setFlowStatus(REVOKE_REDO.getCode(), currTaskIns.getProcessInstanceId());
        // 添加操作记录
        recordService.addTaskRecord(taskHandleDTO.getTaskId(), REVOKE_REDO.getType(), taskHandleDTO.getComment(), null);
    }

    @Transactional(rollbackFor = Exception.class)
    public void transferTask(WorkFlowTaskHandleDTO taskHandleDTO) {
        Task task = transferAndDelegateSupport(taskHandleDTO.getTaskId());
        if (taskHandleDTO.getToUserId() != null) {
            // 转办用户
            taskService.setAssignee(taskHandleDTO.getTaskId(), taskHandleDTO.getToUserId().toString());
        } else if (taskHandleDTO.getOid() != null) {
            // 转办组
            taskService.setAssignee(taskHandleDTO.getTaskId(), null);
            taskService.addCandidateGroup(taskHandleDTO.getTaskId(), taskHandleDTO.getOid().toString());
        }

        String jsonData = null;
        if (ObjectUtil.isNotEmpty(taskHandleDTO.getVariables())) {
            workFlowService.initDefaultVariables(taskHandleDTO.getVariables());
            jsonData = JSONUtil.toJsonStr(taskHandleDTO.getVariables());
            workFlowDataService.updateFormDataByInstanceId(task.getProcessInstanceId(), jsonData);
        }

        // 设置流程状态
        setFlowStatus(TRANSFERRED.getCode(), task.getProcessInstanceId());
        // 添加操作记录
        recordService.addTaskRecord(taskHandleDTO.getTaskId(), TRANSFERRED.getType(), taskHandleDTO.getComment(), jsonData);
    }

    @Transactional(rollbackFor = Exception.class)
    public void delegateTask(WorkFlowTaskHandleDTO taskHandleDTO) {
        Task task = transferAndDelegateSupport(taskHandleDTO.getTaskId());
        if (DelegationState.PENDING == task.getDelegationState()) {
            throw new BusinessException("当前已处于委派任务状态");
        }

        // 委派
        if (taskHandleDTO.getToUserId() != null) {
            taskService.delegateTask(taskHandleDTO.getTaskId(), taskHandleDTO.getToUserId().toString());
        } else if (taskHandleDTO.getOid() != null) {
            task.setAssignee(null);
            if (task.getOwner() == null) {
                task.setOwner(UserContext.get().getId().toString());
            }
            task.setDelegationState(DelegationState.PENDING);
            taskService.saveTask(task);
            taskService.addCandidateGroup(taskHandleDTO.getTaskId(), taskHandleDTO.getOid().toString());
        }

        String jsonData = null;
        if (ObjectUtil.isNotEmpty(taskHandleDTO.getVariables())) {
            workFlowService.initDefaultVariables(taskHandleDTO.getVariables());
            jsonData = JSONUtil.toJsonStr(taskHandleDTO.getVariables());
            workFlowDataService.updateFormDataByInstanceId(task.getProcessInstanceId(), jsonData);
        }

        // 设置流程状态
        setFlowStatus(DELEGATED.getCode(), task.getProcessInstanceId());
        // 添加操作记录
        recordService.addTaskRecord(taskHandleDTO.getTaskId(), DELEGATED.getType(), taskHandleDTO.getComment(), jsonData);
    }

    @Transactional(rollbackFor = Exception.class)
    public void claim(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        Preconditions.checkArgument(task != null,"获取任务信息失败");

        try {
            taskService.claim(taskId, UserContext.get().getId().toString());
        } catch (FlowableTaskAlreadyClaimedException e) {
            throw new BusinessException("当前任务已被其他人认领");
        }

        taskService.setVariableLocal(taskId, CLAIM_SIGN, true);
        // 设置流程状态
        setFlowStatus(CLAIM.getCode(), task.getProcessInstanceId());
        // 添加操作记录
        recordService.addTaskRecord(taskId, CLAIM.getType(), null, null);
    }

    public void unClaim(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        Preconditions.checkArgument(task != null,"获取任务信息失败");

        if (!UserContext.get().getId().toString().equals(task.getAssignee())) {
            throw new BusinessException(20001, "无操作权限");
        }

        taskService.unclaim(taskId);
    }

    public void dynamicAllocation(WorkFlowDynamicAllocationDTO allocation) {
        if (StringUtils.isBlank(allocation.getTaskId()) || allocation.getAllocationType() == null) {
            return;
        }

        if (allocation.getOid() == null && CollectionUtils.isEmpty(allocation.getUserIdList())) {
            return;
        }

        taskService.setVariable(allocation.getTaskId(), TASK_DYNAMIC_HANDLER, allocation);
    }

    public void urgingTask(String instanceId, Integer type, String content) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).active().singleResult();
        Preconditions.checkArgument(processInstance != null,"流程已结束或已挂起，无法执行撤回操作");

        WorkFlowUrgingTypeEnum typeEnum = WorkFlowUrgingTypeEnum.getType(type);
        Preconditions.checkArgument(typeEnum != null, 30001,"催办类型异常");
        List<Integer> userIdList = getUrgingUserIds(instanceId);
        switch (typeEnum) {
            case SYS_NOTICE:
                // 发送系统消息通知
                SysUserVO sysUserVO = UserContext.get();
                HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(historicProcessInstance.getProcessDefinitionId()).singleResult();
                SysNoticeDTO sysNoticeDTO = new SysNoticeDTO();
                sysNoticeDTO.setType(0);
                sysNoticeDTO.setContent(content);
                sysNoticeDTO.setCreateBy(sysUserVO.getName());
                sysNoticeDTO.setCreateUid(sysUserVO.getId());
                sysNoticeDTO.setTitle("【任务催办】" + sysUserVO.getName() + " - " + processDefinition.getName());
                sysNoticeDTO.setUidList(userIdList);
                sysNoticeService.save(sysNoticeDTO);
                break;
            case SMS:
                // todo 暂无短信模板
            case GOV_DING_TALK:
//                List<SysUser> sysUsers = sysUserMapper.selectByIdList(userIdList);
//                if (CollectionUtils.isNotEmpty(sysUsers)) {
//                    String receiverIds = sysUsers.stream().map(SysUser::getZzdId).filter(StringUtils::isNotBlank).collect(Collectors.joining(","));
//                    if (StringUtils.isNotBlank(receiverIds)) {
//                        // 发送工作通知
//                        DingTextMsg dingTextMsg = new DingTextMsg();
//                        dingTextMsg.setMsgtype("text");
//                        DingTextMsg.TextMsg textMsg = new DingTextMsg.TextMsg();
//                        textMsg.setContent(content);
//                        dingTextMsg.setText(textMsg);
//                        govDingService.workNotification(receiverIds,"", JSONUtil.toJsonStr(dingTextMsg));
//                    }
//                }
            default:
        }
    }


    private Task transferAndDelegateSupport(String taskId) {
        // 获取当前用户信息
        SysUserVO currentUser = UserContext.get();
        // 获取当前任务信息
        Task currentTask = taskService.createTaskQuery().taskId(taskId)
                .or()
                .taskCandidateOrAssigned(currentUser.getId().toString())
                .taskCandidateGroupIn(getCurrentOrgIdList(currentUser)).endOr()
                .singleResult();
        Preconditions.checkArgument(currentTask != null, "获取任务信息失败");

        List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(currentTask.getId());
        if (CollectionUtils.isEmpty(identityLinks)) {
            return currentTask;
        }

        // 清除原有的候选人、候选组
        for (IdentityLink identityLink : identityLinks) {
            if (StringUtils.isNotBlank(identityLink.getUserId())) {
                taskService.deleteCandidateUser(currentTask.getId(), identityLink.getUserId());
            }

            if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                taskService.deleteCandidateGroup(currentTask.getId(), identityLink.getGroupId());
            }
        }

        return currentTask;
    }
    private List<Integer> getUrgingUserIds(String instanceId) {
        Set<Integer> userIdList = new HashSet<>();
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(instanceId).list();
        for (Task task : tasks) {
            List<Integer> taskRelatedUserIds = workFlowService.getTaskRelatedUserIds(task.getId());
            if (CollectionUtils.isNotEmpty(taskRelatedUserIds)) {
                userIdList.addAll(taskRelatedUserIds);
            }
        }
        return new ArrayList<>(userIdList);
    }

    private void setFlowStatus(String code, String instanceId) {
        if (StringUtils.isBlank(code) || StringUtils.isBlank(instanceId)) {
            return;
        }

        WorkFlowButton workFlowButton = workFlowButtonService.getByCode(code);
        if (workFlowButton == null || workFlowButton.getFlowStatus() == null) {
            return;
        }


        WorkFlowData workFlowData = workFlowDataService.getFormDataByInstanceId(instanceId);
        if (workFlowData == null) {
            return;
        }

        // 设置流程状态
        workFlowData.setStatus(workFlowButton.getFlowStatus());
        workFlowDataService.updateById(workFlowData);
    }
    private void checkTaskReturn(SysUserVO sysUserVO, Task task) {
        String variableName = TASK_RETURN_LIMIT + task.getTaskDefinitionKey();
        WorkFlowTaskReturnLimitDTO taskReturnLimit = (WorkFlowTaskReturnLimitDTO) taskService.getVariable(task.getId(), variableName);
        if (taskReturnLimit == null || taskReturnLimit.getLimitType() == null || taskReturnLimit.getLimitCount() == null) {
            return;
        }

        int count;
        switch (taskReturnLimit.getLimitType()) {
            case 0:
                Map<Integer, Integer> userMap = taskReturnLimit.getUserMap();
                count = userMap.containsKey(sysUserVO.getId()) ? userMap.get(sysUserVO.getId()) + 1 : 1;
                userMap.put(sysUserVO.getId(), count);
                break;
            case 1:
                Map<Integer, Integer> orgMap = taskReturnLimit.getOrgMap();
                count = orgMap.containsKey(sysUserVO.getActiveOid()) ? orgMap.get(sysUserVO.getActiveOid()) + 1 : 1;
                orgMap.put(sysUserVO.getActiveOid(), count);
                break;
            default:
                throw new BusinessException("LimitType参数异常");
        }

        if (count > taskReturnLimit.getLimitCount()) {
            throw new BusinessException("退回次数已达到上限");
        }

        taskService.setVariable(task.getId(), variableName, taskReturnLimit);
    }

    private String getReturnTargetKey(FlowElement source, Task task) {
        String targetTaskKey = null;
        // 判断是否存在退回配置
        ExtensionElement extensionElement = WorkFlowUtil.getExtensionElement(source, EXTENSION_ELEMENT_TASK_RETURN);
        if (extensionElement != null) {
            targetTaskKey = extensionElement.getAttributeValue(null, EXTENSION_ELEMENT_TASK_RETURN_TARGET_KEY);
        }

        if (StringUtils.isBlank(targetTaskKey)) {
            // 迭代向前查找获取上一步的所有用户节点
            List<UserTask> parentUserTasks = WorkFlowUtil.iteratorFindParentUserTasks(source, null, null);
            Preconditions.checkArgument(CollectionUtils.isNotEmpty(parentUserTasks), "当前节点不支持退回操作");

            // 获取历史已完成的用户节点列表
            List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId()).finished().taskWithoutDeleteReason().list();
            Preconditions.checkArgument(CollectionUtils.isNotEmpty(historicTaskInstances),"当前节点不支持退回操作");
            historicTaskInstances.removeIf(his -> his.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));

            // 获取两个集合的交集，即实际的上一步的节点key
            List<String> parentUserTaskIds = parentUserTasks.stream().map(UserTask::getId).collect(Collectors.toList());
            List<String> hisTaskFinishedKeys = historicTaskInstances.stream().map(HistoricTaskInstance::getTaskDefinitionKey).distinct().collect(Collectors.toList());
            List<String> actualParentUserTaskIds = (List<String>) CollectionUtils.intersection(parentUserTaskIds, hisTaskFinishedKeys);
            Preconditions.checkArgument(CollectionUtils.isNotEmpty(actualParentUserTaskIds),"当前节点不支持退回操作");
            Preconditions.checkArgument(actualParentUserTaskIds.size() <= 1, "当前节点不支持退回操作");
            targetTaskKey = actualParentUserTaskIds.get(0);
        }
        return targetTaskKey;
    }


    private List<String> checkGatewayCondition(BpmnModel bpmnModel, Task task) {
        // 判断当前节点是否在并行或包容网关内
        FlowElement flowElement = WorkFlowUtil.getParallelGateway(bpmnModel, task.getTaskDefinitionKey());
        if (flowElement == null) {
            flowElement = WorkFlowUtil.getInclusiveGateway(bpmnModel, task.getTaskDefinitionKey());
        }

        if (flowElement == null) {
            return Collections.emptyList();
        }

        List<UserTask> parallelUserTasks = WorkFlowUtil.findNextUserTasks(flowElement);
        List<String> keys = parallelUserTasks.stream().map(UserTask::getId).collect(Collectors.toList());
        List<ActivityInstance> activityInstances = runtimeService.createNativeActivityInstanceQuery()
                .sql("SELECT * FROM act_ru_actinst WHERE proc_inst_id_ = #{instanceId} AND act_type_ = 'userTask' AND start_time_ > (SELECT start_time_ FROM act_ru_actinst WHERE proc_inst_id_ = #{instanceId} AND act_id_ = #{actId} ORDER BY start_time_ DESC LIMIT 1)")
                .parameter("instanceId", task.getProcessInstanceId()).parameter("actId", flowElement.getId()).list();
        if (CollectionUtils.isEmpty(activityInstances)) {
            return Collections.emptyList();
        }

        for (ActivityInstance activityInstance : activityInstances) {
            if (activityInstance.getTaskId().equals(task.getId())) {
                continue;
            }

            if (keys.contains(activityInstance.getActivityId()) && activityInstance.getEndTime() != null) {
                throw new BusinessException("并行或包容网关中其他用户节点已办结，无法进行退回操作");
            }
        }

        return keys;
    }
}
