package cn.iocoder.yudao.module.bpm.service.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
import cn.iocoder.yudao.module.bpm.enums.task.*;
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalaryService;
import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO;
import cn.iocoder.yudao.module.smartfactory.api.factoryInfo.FactoryInfoApi;
import cn.iocoder.yudao.module.smartfactory.api.factoryInfo.dto.FactoryInfoDTO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;

/**
 * 流程任务实例 Service 实现类
 *
 * @author jason
 */
@Slf4j
@Service
public class BpmTaskServiceImpl implements BpmTaskService {

    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    @Resource
    private RuntimeService runtimeService;

    @Resource
    @Lazy // 解决循环依赖
    private BpmProcessInstanceService processInstanceService;
    @Resource
    private BpmModelService bpmModelService;
    @Resource
    private BpmMessageService messageService;

    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private DeptApi deptApi;

    @Resource
    private FactoryInfoApi factoryInfoApi;

    @Resource
    private BpmTaskExtMapper taskExtMapper;

    @Resource
    private ManagementService managementService;

    @Resource
    private BpmProcessInstanceExtMapper processInstanceExtMapper;

    @Resource
    private BpmOASalaryService salaryService;

    @Override
    public PageResult<BpmTaskCCPageItemRespVO> getCCTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) {
        // 查询被抄送的Task
        BpmProcessInstanceMyPageReqVO reqVO = BeanUtils.toBean(pageVO, BpmProcessInstanceMyPageReqVO.class);
//        reqVO.setName(pageVO.getName());
//        reqVO.setCreateTime(pageVO.getCreateTime());

        // 判断搜索条件是否选择用户
        if (pageVO.getUserId() != null) {
            reqVO.setUserIds(new Long[]{pageVO.getUserId()});
        }else if (pageVO.getDeptId() != null) {

            List<AdminUserRespDTO> users = adminUserApi.getUserByDeptIdAll(pageVO.getDeptId()).getCheckedData();
            List<Long> userIds = users.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList());

            if (CollUtil.isNotEmpty(userIds)) {
                reqVO.setUserIds(userIds.toArray(new Long[0]));
            }
        }

        // 通过 BpmProcessInstanceExtDO 表，先查询到对应的分页
        PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectCCPage(userId, reqVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return new PageResult<>(pageResult.getTotal());
        }
        // 获得流程 Task Map
        List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId);
        // 获得 TaskExtDO Map
        List<BpmTaskExtDO> bpmTaskExtDOs = getTaskByProcessInstanceIdAndResult(processInstanceIds, null);
        Map<String, List<BpmTaskExtDO>> bpmTaskExtDOMap = convertMultiMap(bpmTaskExtDOs, BpmTaskExtDO::getProcessInstanceId);

        // 获得 ProcessInstance Map
        Set<String> ids = new HashSet<>(processInstanceIds);

        Map<String, HistoricProcessInstance> historicProcessInstanceMap =
                processInstanceService.getHistoricProcessInstanceMap(ids);

        // 获得 User Map
        List<Long> userIds = convertList(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()));
        userIds.addAll(convertList(bpmTaskExtDOs, BpmTaskExtDO::getAssigneeUserId));
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(new HashSet<>(userIds));
        // 拼接结果
        return new PageResult<>(BpmTaskConvert.INSTANCE.convertListCC(pageResult.getList(), bpmTaskExtDOMap, historicProcessInstanceMap, userMap), pageResult.getTotal());
    }

    @Override
    public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
        // 查询待办任务
        TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己
                //只能查询流程标识定义为oa开头的流程
                .processDefinitionKeyLike("oa_%")
                .orderByTaskCreateTime().desc(); // 创建时间倒序
        if (StrUtil.isNotBlank(pageVO.getName())) {
            //流程定义的名称
            taskQuery.processDefinitionName(pageVO.getName());

//            taskQuery.taskNameLike("%" + pageVO.getName() + "%");
        }
        if (ArrayUtil.get(pageVO.getCreateTime(), 0) != null) {
            taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0]));
        }
        if (ArrayUtil.get(pageVO.getCreateTime(), 1) != null) {
            taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1]));
        }


        // 执行查询
        List<Task> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
        if (CollUtil.isEmpty(tasks)) {
            return PageResult.empty(taskQuery.count());
        }

        // 获得 ProcessInstance Map
        Map<String, ProcessInstance> processInstanceMap =
                processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId));
        // 获得 User Map
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
        // 拼接结果
        return new PageResult<>(BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap),
                taskQuery.count());
    }

    @Override
    public PageResult<BpmTaskTodoPageRespVO> getTodoTaskPage1(Long userId, BpmTaskTodoPageReqVO pageReqVO) {

        Page<BpmTaskTodoPageRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        IPage<BpmTaskTodoPageRespVO> pageResp = taskExtMapper.selectTodoTaskPage(page, pageReqVO, userId);

        /*
                临时处理，列表中薪资付款 展示具体公司名称问题
                begin
         */
        // 获取所有薪资付款的流程实例
        List<String> processInstanceIds = pageResp.getRecords().stream()
                .filter(item -> item.getProcessDefinitionId().contains("oa_salary"))
                .map(BpmTaskTodoPageRespVO::getProcessInstanceId)
                .collect(Collectors.toList());

        // 获取薪资付款列表
        List<BpmOASalaryDO> salaryDOS = salaryService.getListByProcessInstanceIds(processInstanceIds);
        // 获取公司编号map
        Map<String, Long> salaryDeptMap = salaryDOS.stream()
                .filter(item -> item.getCompanyDeptId() != null)
                .collect(Collectors.toMap(BpmOASalaryDO::getProcessInstanceId, BpmOASalaryDO::getCompanyDeptId));
        // 获取工厂编号Map
        Map<String, Set<Long>> factoryDeptMap = salaryDOS.stream()
                .filter(item -> CollUtil.isNotEmpty(item.getFactoryDeptId()))
                .collect(Collectors.toMap(BpmOASalaryDO::getProcessInstanceId, BpmOASalaryDO::getFactoryDeptId));
        // 获取付款部门信息
        Map<Long, DeptRespDTO> dtoMap = deptApi.getDeptMap(convertSet(salaryDOS, BpmOASalaryDO::getCompanyDeptId));
        // 获取付款工厂信息
        Map<Long, FactoryInfoDTO> factoryInfoDTOMap = factoryInfoApi.getFactoryMap(factoryDeptMap.values()
                .stream()
                .flatMap(Set::stream)
                .collect(Collectors.toSet()));
        // 组合数据
        Map<String, List<FactoryInfoDTO>> groupedMap = factoryDeptMap.entrySet()
                .stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().stream()
                                .map(factoryInfoDTOMap::get)
                                .filter(Objects::nonNull)
                                .collect(Collectors.toList())
                ));

        pageResp.getRecords().forEach(item -> {
            if (salaryDeptMap.containsKey(item.getProcessInstanceId())) {
                item.setStartUserNickname(item.getStartUserNickname() +
                        "(" +
                        dtoMap.get(salaryDeptMap.get(item.getProcessInstanceId())).getName() +
                        ")");
            }else if (factoryDeptMap.containsKey(item.getProcessInstanceId())) {
                item.setStartUserNickname(item.getStartUserNickname() +
                        "(" +
                        groupedMap.get(item.getProcessInstanceId()).stream()
                                .map(FactoryInfoDTO::getShortName)
                                .collect(Collectors.joining(",")) +
                        ")");
            }
        });

        return new PageResult<>(pageResp.getRecords(), pageResp.getTotal());
    }

    @Override
    public PageResult<BpmTaskDonePageRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) {

        // 判断搜索条件是否选择用户
        List<Long> userIds = null;
        if (pageVO.getUserId() != null) {
            userIds = Collections.singletonList(pageVO.getUserId());
        }else if (pageVO.getDeptId() != null) {

            List<AdminUserRespDTO> users = adminUserApi.getUserByDeptIdAll(pageVO.getDeptId()).getCheckedData();
            userIds = users.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList());
        }

        // 获取待办任务
        PageResult<BpmTaskDonePageRespVO> pageResult = taskExtMapper.selectDonePage(userId, pageVO, userIds);
        if (CollUtil.isNotEmpty(pageResult.getList())) {

            // 获取用户编号集合
            Set<Long> startUserIds = convertSet(pageResult.getList(), BpmTaskDonePageRespVO::getStartUserId);
            // 获得 User Map
            Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(startUserIds);

            /*
                临时处理，列表中薪资付款 展示具体公司名称问题
                begin
             */
            // 获取所有薪资付款的流程实例
            List<String> processInstanceIds = pageResult.getList().stream()
                    .filter(item -> item.getProcessDefinitionId().contains("oa_salary"))
                    .map(BpmTaskDonePageRespVO::getProcessInstanceId)
                    .collect(Collectors.toList());

            // 获取薪资付款列表
            List<BpmOASalaryDO> salaryDOS = salaryService.getListByProcessInstanceIds(processInstanceIds);
            Map<String, Long> salaryDeptMap = salaryDOS.stream()
                    .filter(item -> item.getCompanyDeptId() != null)
                    .collect(Collectors.toMap(BpmOASalaryDO::getProcessInstanceId, BpmOASalaryDO::getCompanyDeptId));
            // 获取付款部门信息
            Map<Long, DeptRespDTO> dtoMap = deptApi.getDeptMap(convertSet(salaryDOS, BpmOASalaryDO::getCompanyDeptId));

            // 获取工厂编号Map
            Map<String, Set<Long>> factoryDeptMap = salaryDOS.stream()
                    .filter(item -> CollUtil.isNotEmpty(item.getFactoryDeptId()))
                    .collect(Collectors.toMap(BpmOASalaryDO::getProcessInstanceId, BpmOASalaryDO::getFactoryDeptId));
            // 获取付款工厂信息
            Map<Long, FactoryInfoDTO> factoryInfoDTOMap = factoryInfoApi.getFactoryMap(factoryDeptMap.values()
                    .stream()
                    .flatMap(Set::stream)
                    .collect(Collectors.toSet()));
            // 组合数据
            Map<String, List<FactoryInfoDTO>> groupedMap = factoryDeptMap.entrySet()
                    .stream()
                    .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            entry -> entry.getValue().stream()
                                    .map(factoryInfoDTOMap::get)
                                    .filter(Objects::nonNull)
                                    .collect(Collectors.toList())
                    ));

            pageResult.getList().forEach(item -> {
                item.setStartUserNickname(userMap.get(item.getStartUserId()).getNickname());
                if (salaryDeptMap.containsKey(item.getProcessInstanceId())) {
                    item.setStartUserNickname(item.getStartUserNickname() +
                            "(" +
                            dtoMap.get(salaryDeptMap.get(item.getProcessInstanceId())).getName() +
                            ")");
                }else if (factoryDeptMap.containsKey(item.getProcessInstanceId())) {
                    item.setStartUserNickname(item.getStartUserNickname() +
                            "(" +
                            groupedMap.get(item.getProcessInstanceId()).stream()
                                    .map(FactoryInfoDTO::getShortName)
                                    .collect(Collectors.joining(",")) +
                            ")");
                }
            });
        }

        return pageResult;

//        //查询bpm_task_ext扩展表， 接受人是自己，不是自动审批的任务, 按任务名称分组
//        LambdaQueryWrapperX<BpmTaskExtDO> queryWrapperX = new LambdaQueryWrapperX<>();
//        queryWrapperX.eq(BpmTaskExtDO::getAssigneeUserId, userId);
//        queryWrapperX.ne(BpmTaskExtDO::getReason, BpmConstants.AUTO_APPRAVAL);
//        queryWrapperX.eq(BpmTaskExtDO::getDeleted, false);
//        queryWrapperX.groupBy(BpmTaskExtDO::getName);
//        queryWrapperX.select(BpmTaskExtDO::getName);
//        //只能查询流程标识定义为oa开头的流程
//        queryWrapperX.likeIfPresent(BpmTaskExtDO::getProcessDefinitionId,"oa_");
//        List<BpmTaskExtDO> list = taskExtMapper.selectList(queryWrapperX);
//        List<String> taskNames = list.stream().map(BpmTaskExtDO::getName)
//                .collect(Collectors.toList());
//
//        // 查询已办任务
//        HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成
//                .taskAssignee(String.valueOf(userId)) // 分配给自己
//                .processDefinitionKeyLike("oa_%")
//                .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序
//        if (taskNames != null && !taskNames.isEmpty()) {
//            /**
//             * 条件是： 已被分配的任务的名称分组数据，作为条件查询
//             */
//            taskQuery.taskNameIn(taskNames);
//        } else {
//            /**
//             * taskNames是空或者没有数据，表示没有任何分配给自己的任务，且分自动审批的任务。
//             * 那么就输出一个不存在的任务名称，可以让数据查询不出来
//             */
//            taskQuery.taskName("//////");
//        }
//
//        if (StrUtil.isNotBlank(pageVO.getName())) {
////            taskQuery.taskNameLike("%" + pageVO.getName() + "%");
//            //流程定义的名称
//            taskQuery.processDefinitionName(pageVO.getName());
//        }
//        LocalDateTime[] localDateTimes = pageVO.getCreateTime();
//        if (localDateTimes != null) {
//            if (localDateTimes[0] != null) {
//                taskQuery.taskCreatedAfter(DateUtils.of(localDateTimes[0]));
//            }
//            if (localDateTimes[1] != null) {
//                taskQuery.taskCreatedBefore(DateUtils.of(localDateTimes[1]));
//            }
//        }
//
//        // 执行查询
//        List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
//        if (CollUtil.isEmpty(tasks)) {
//            return PageResult.empty(taskQuery.count());
//        }
//
//        // 获得 TaskExtDO Map
//        List<BpmTaskExtDO> bpmTaskExtDOs =
//                taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
//        Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
////        // 获得 ProcessInstance Map
////        Map<String, HistoricProcessInstance> historicProcessInstanceMap =
////                processInstanceService.getHistoricProcessInstanceMap(
////                        convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
//
//        // 获得 ProcessInstance，
//        List<HistoricProcessInstance> historicProcessInstances = processInstanceService.getHistoricProcessInstances(
//                convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
//
//        // 判断搜索条件是否选择用户
//        if (pageVO.getUserId() != null) {
//            // 筛选出 发起人是pageVO.getUserId() 的流程实例
//            historicProcessInstances = historicProcessInstances.stream()
//                    .filter(instance -> instance.getStartUserId().equals(pageVO.getUserId().toString()))
//                    .collect(Collectors.toList());
//
//            // 同步筛选掉 task记录
//            List<String> processInstanceIds = convertList(historicProcessInstances, HistoricProcessInstance::getId);
//            tasks = tasks.stream().filter(task -> processInstanceIds.contains(task.getProcessInstanceId())).collect(Collectors.toList());
//        }else if (pageVO.getDeptId() != null) {
//
//            List<AdminUserRespDTO> users = adminUserApi.getUserByDeptIdAll(pageVO.getDeptId()).getCheckedData();
//            List<Long> userIds = users.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList());
//
//            historicProcessInstances = historicProcessInstances.stream()
//                    .filter(instance -> userIds.contains(Long.valueOf(instance.getStartUserId())))
//                    .collect(Collectors.toList());
//
//            // 同步筛选掉 task记录
//            List<String> processInstanceIds = convertList(historicProcessInstances, HistoricProcessInstance::getId);
//            tasks = tasks.stream().filter(task -> processInstanceIds.contains(task.getProcessInstanceId())).collect(Collectors.toList());
//        }
//
//        // 获得 ProcessInstance Map
//        Map<String, HistoricProcessInstance> historicProcessInstanceMap = convertMap(historicProcessInstances, HistoricProcessInstance::getId);
//
//        // 获得 User Map
//        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
//                convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
//        // 拼接结果
//        return new PageResult<>(
//                BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap),
//                taskQuery.count());

//        // 获得 TaskExtDO Map
//        List<BpmTaskExtDO> bpmTaskExtDOsTemp =
//                taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
//        /** 剔除自动审批的Task记录  add by yj at 2024.1.23 Begin*/
//        List<BpmTaskExtDO> bpmTaskExtDOs = new ArrayList<>() ;
//        List<HistoricTaskInstance> tasksAfter = new ArrayList<>() ;
//        for (BpmTaskExtDO bpmTaskExtDO : bpmTaskExtDOsTemp) {
//            String reason = bpmTaskExtDO.getReason() ;
//            if(!BpmConstants.AUTO_APPRAVAL.equals(reason)) {
//                bpmTaskExtDOs.add(bpmTaskExtDO) ;
//                String taskId = bpmTaskExtDO.getTaskId() ;
//                for (HistoricTaskInstance historicTaskInstance : tasks) {
//                    String id= historicTaskInstance.getId() ;
//                    if(taskId.equals( id )) {
//                        tasksAfter.add(historicTaskInstance) ;
//                        break ;
//                    }
//                }
//            }
//        }
//        tasks = tasksAfter ;
//        /** 剔除自动审批的Task记录  add by yj at 2024.1.23 End*/
//
//        Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOsTemp, BpmTaskExtDO::getTaskId);
//        // 获得 ProcessInstance Map
//        Map<String, HistoricProcessInstance> historicProcessInstanceMap =
//                processInstanceService.getHistoricProcessInstanceMap(
//                        convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
//        // 获得 User Map
//        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
//                convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
//        // 拼接结果
//        return new PageResult<>(
//                BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap),
//                taskQuery.count()  //这里就不使用从bpm表中获取的task数量， 本自己扩展的数据库表bpm_task_ext的数据
////                new Long(bpmTaskExtDOs.size())
//        );
    }

    @Override
    public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
        if (CollUtil.isEmpty(processInstanceIds)) {
            return Collections.emptyList();
        }
        return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
    }

    @Override
    public List<Task> getTasksByProcessInstanceId(String processInstanceId) {

        return taskService.createTaskQuery().processInstanceId(processInstanceId).orderByTaskCreateTime().desc().list();
    }

    @Override
    public List<HistoricTaskInstance> getListTasksByProcessInstanceId(String processInstanceId) {

        return historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
                .orderByTaskCreateTime().desc().finished().list();
    }

    @Override
    public List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId) {
        // 获得任务列表
        List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序
                .list();
        if (CollUtil.isEmpty(tasks)) {
            return Collections.emptyList();
        }

        // 获得 TaskExtDO Map
        List<BpmTaskExtDO> bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));

        /* 剔除自动审批的Task记录  Begin */
        bpmTaskExtDOs = bpmTaskExtDOs.stream()
                .filter(bpmTaskExtDO -> !BpmConstants.AUTO_APPRAVAL.equals(bpmTaskExtDO.getReason()) || BpmConstants.SELF_TASK_NAME.equals(bpmTaskExtDO.getName()))
                .collect(Collectors.toList());

        List<String> taskIds = convertList(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
        tasks = tasks.stream().filter(task -> taskIds.contains(task.getId())).collect(Collectors.toList());
        /* 剔除自动审批的Task记录  End */

        Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
        // 获得 ProcessInstance Map
        HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId);
        // 获得 User Map
        Set<Long> userIds = convertSet(tasks, task -> NumberUtils.parseLong(StrUtil.isEmpty(task.getAssignee())?task.getOwner():task.getAssignee()));
        userIds.add(NumberUtils.parseLong(processInstance.getStartUserId()));
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
        // 获得 Dept Map
        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));

        // 拼接数据
        List<BpmTaskRespVO> result = BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap);
        return BpmTaskConvert.INSTANCE.convertChildrenList(result);
    }

    @Override
    public Map<String, List<BpmTaskRespVO>> getTaskListByProcessInstanceIds(List<String> processInstanceIds) {

        Map<String, List<BpmTaskRespVO>> respVOS = new HashMap<>();

        // 获得任务列表
        List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceIdIn(processInstanceIds)
                .orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序
                .list();
        if (CollUtil.isEmpty(tasks)) {
            return null;
        }

        // 获得任务列表
        List<BpmTaskExtDO> bpmTaskExtDOs = taskExtMapper.selectList(BpmTaskExtDO::getProcessInstanceId, processInstanceIds);

        /* 剔除自动审批的Task记录 */
        bpmTaskExtDOs = bpmTaskExtDOs.stream()
                .filter(bpmTaskExtDO -> !BpmConstants.AUTO_APPRAVAL.equals(bpmTaskExtDO.getReason()) || BpmConstants.SELF_TASK_NAME.equals(bpmTaskExtDO.getName()))
                .collect(Collectors.toList());
        List<String> taskIds = convertList(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
        tasks = tasks.stream().filter(task -> taskIds.contains(task.getId())).collect(Collectors.toList());

        // 获得 User Map
        Set<Long> userIds = convertSet(bpmTaskExtDOs, BpmTaskExtDO::getAssigneeUserId);
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
        // 获得 Dept Map
        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));

        // 获得BpmTaskExtDO map
        Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);

        // 获得 task MAP
        Map<String, List<HistoricTaskInstance>> taskMap = convertMultiMap(tasks, HistoricTaskInstance::getProcessInstanceId);
        taskMap.forEach((processInstanceId, taskList) -> {

            // 拼接数据
            List<BpmTaskRespVO> result = BpmTaskConvert.INSTANCE.convertList3(taskList, bpmTaskExtDOMap, null, userMap, deptMap);

            respVOS.put(processInstanceId, result);
        });

        return respVOS;
    }

    @Override
    public List<BpmTaskExtDO> getTaskListByTaskIdList(List<String> taskIdList) {
        return taskExtMapper.selectListByTaskIds(taskIdList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) {
        // 1.1 校验任务存在
        Task task = validateTask(userId, reqVO.getId());
        // 1.2 校验流程实例存在
        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
        if (instance == null) {
            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
        }

        // 情况一：被委派的任务，不调用 complete 去完成任务
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            approveDelegateTask(reqVO, task);
            return;
        }

        // 情况二：后加签的任务
        if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(task.getScopeType())) {
            // 后加签处理
            approveAfterSignTask(task, reqVO);
            return;
        }

        // 情况三：自己审批的任务，调用 complete 去完成任务
        // 完成任务，审批通过，并设置paramMap的post_id值
        // paramMap 中的值，可用于流程图中分支路线条件
        /*
         * 判定流程的走向，这里是流程审核节点（就是流程设计中的任意审核节点）
         * 根据当前审核人的岗位判定流程走向
         */
        List<ProcessInstanceVariablesDTO> variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId());
        Map<String, Object> paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue));

        // 获得审批人User
        AdminUserRespDTO examineUser = adminUserApi.getUser(userId).getCheckedData();
        //获取流程审批人部门信息
        DeptRespDTO examineDept = deptApi.getDept(examineUser.getDeptId()).getCheckedData();

        if (CollectionUtil.isEmpty(examineUser.getPostIds())) {
            // 当前审批用户未配置岗位
            // 操作失败，原因：您未配置岗位，请联系管理员操作
            throw exception(TASK_OPERATE_FAIL_USER_NO_POST);
        }
        if( examineUser.getDeptId() == null ) {
            // 当前审批用户未配置部门
            // 操作失败，原因：您未配置部门，请联系管理员操作
            throw exception(TASK_OPERATE_FAIL_USER_NO_DEPT);
        }

        //根据审批人用户ID，获取审批人 担任的负责人的部门信息
        List<DeptRespDTO> deptRespDTOs = deptApi.getDeptByLeaderId(userId).getCheckedData();

        // 设置审批人所在部门的负责人和部门层级
        paramMap.put("leader_id", examineDept.getLeaderUserId().toString());
        paramMap.put("level", examineDept.getLevel().toString());
        //遍历查找， 发起人的上级部门
        for (DeptRespDTO deptRespDTO : deptRespDTOs) {
            if (paramMap.get("dept_flag").toString().contains(deptRespDTO.getFlag())) {

                paramMap.put("level", deptRespDTO.getLevel().toString());
                break;
            }
        }

        paramMap.put("approve_reason", reqVO.getReason()); //通过原因---因为Task任务的通过，是通过监听事件处理的，reason数据无法传递给监听函数。所以通过此中方法传递
        taskService.complete(task.getId(), paramMap);
        // 更新任务拓展表为通过
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
                        .setReason(reqVO.getReason()));
        // 处理加签任务
        handleParentTask(task);
    }


    /**
     * 审批通过存在“后加签”的任务。
     * <p>
     * 注意：该任务不能马上完成，需要一个中间状态（SIGN_AFTER），并激活剩余所有子任务（PROCESS）为可审批处理
     *
     * @param task  当前任务
     * @param reqVO 前端请求参数
     */
    private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) {
        // 1. 有向后加签，则该任务状态临时设置为 ADD_SIGN_AFTER 状态
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult())
                        .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now()));

        // 2. 激活子任务
        List<String> childrenTaskIdList = getChildrenTaskIdList(task.getId());
        for (String childrenTaskId : childrenTaskIdList) {
            taskService.resolveTask(childrenTaskId);
        }
        // 2.1 更新任务扩展表中子任务为进行中
        taskExtMapper.updateBatchByTaskIdList(childrenTaskIdList,
                new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));
    }

    /**
     * 处理当前任务的父任务，主要处理“加签”的情况
     *
     * @param task 当前任务
     */
    private void handleParentTask(Task task) {
        String parentTaskId = task.getParentTaskId();
        if (StrUtil.isBlank(parentTaskId)) {
            return;
        }
        // 1. 判断当前任务的父任务是否还有子任务
        Long childrenTaskCount = getChildrenTaskCount(parentTaskId);
        if (childrenTaskCount > 0) {
            return;
        }
        // 2. 获取父任务
        Task parentTask = validateTaskExist(parentTaskId);

        // 3. 处理加签情况
        String scopeType = parentTask.getScopeType();
        if (!validateSignType(scopeType)) {
            return;
        }
        // 3.1 情况一：处理向前加签
        if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {
            // 3.1.1 如果是向前加签的任务，则调用 resolveTask 指派父任务，将 owner 重新赋值给父任务的 assignee，这样它就可以被审批
            taskService.resolveTask(parentTaskId);
            // 3.1.2 更新任务拓展表为处理中
            taskExtMapper.updateByTaskId(
                    new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));
        } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) {
            // 3.2 情况二：处理向后加签
            handleParentTaskForAfterSign(parentTask);
        }

        // 4. 子任务已处理完成，清空 scopeType 字段，修改 parentTask 信息，方便后续可以继续向前后向后加签
        // 再查询一次的原因是避免报错：Task was updated by another transaction concurrently
        // 因为前面处理后可能会导致 parentTask rev 字段被修改，需要重新获取最新的
        parentTask = getTask(parentTaskId);
        if (parentTask == null) {
            // 为空的情况是：已经通过 handleAfterSign 方法将任务完成了，所以 ru_task 表会查不到数据
            return;
        }
        clearTaskScopeTypeAndSave(parentTask);
    }


    /**
     * 处理后加签任务
     *
     * @param parentTask 当前审批任务的父任务
     */
    // TODO @海：这个逻辑，怎么感觉可以是 parentTask 的 parent，再去调用 handleParentTask 方法；可以微信聊下；
    private void handleParentTaskForAfterSign(Task parentTask) {
        String parentTaskId = parentTask.getId();
        // 1. 更新 parentTask 的任务拓展表为通过，并调用 complete 完成自己
        BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId());
        BpmTaskExtDO currentTaskExtUpdateObj = new BpmTaskExtDO().setTaskId(parentTask.getId())
                .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
        if (currentTaskExt.getEndTime() == null) {
            // 1.1 有这个判断是因为,以前没设置过结束时间，才去设置
            currentTaskExtUpdateObj.setEndTime(LocalDateTime.now());
        }
        taskExtMapper.updateByTaskId(currentTaskExtUpdateObj);
        // 1.2 完成自己（因为它已经没有子任务，所以也可以完成）
        taskService.complete(parentTaskId);

        // 2. 如果有父级，递归查询上级任务是否都已经完成
        if (StrUtil.isEmpty(parentTask.getParentTaskId())) {
            return;
        }
        // 2.1 判断整条链路的任务是否完成
        // 例如从 A 任务加签了一个 B 任务，B 任务又加签了一个 C 任务，C 任务加签了 D 任务
        // 此时，D 任务完成，要一直往上找到祖先任务 A调用 complete 方法完成 A 任务
        boolean allChildrenTaskFinish = true;
        while (StrUtil.isNotBlank(parentTask.getParentTaskId())) {
            parentTask = validateTaskExist(parentTask.getParentTaskId());
            BpmTaskExtDO parentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId());
            if (parentTaskExt == null) {
                break;
            }
            boolean currentTaskFinish = BpmProcessInstanceResultEnum.isEndResult(parentTaskExt.getResult());
            // 2.2 如果 allChildrenTaskFinish 已经被赋值为 false，则不会再赋值为 true，因为整个链路没有完成
            if (allChildrenTaskFinish) {
                allChildrenTaskFinish = currentTaskFinish;
            }
            // 2.3 任务已完成则不处理
            if (currentTaskFinish) {
                continue;
            }

            // 3 处理非完成状态的任务
            // 3.1 判断当前任务的父任务是否还有子任务
            Long childrenTaskCount = getChildrenTaskCount(parentTaskExt.getTaskId());
            if (childrenTaskCount > 0) {
                continue;
            }
            // 3.2 没有子任务，判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成
            if (BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult().equals(parentTaskExt.getResult())) {
                // 3.3 需要修改该任务状态为处理中
                taskService.resolveTask(parentTaskExt.getTaskId());
                parentTaskExt.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
                taskExtMapper.updateByTaskId(parentTaskExt);
            }
            // 3.4 清空 scopeType 字段，用于任务没有子任务时使用该方法，方便任务可以再次被不同的方式加签
            parentTask = validateTaskExist(parentTaskExt.getTaskId());
            clearTaskScopeTypeAndSave(parentTask);
        }

        // 4. 完成最后的顶级祖先任务
        if (allChildrenTaskFinish) {
            taskService.complete(parentTask.getId());
        }
    }

    /**
     * 清空 scopeType 字段，用于任务没有子任务时使用该方法，方便任务可以再次被不同的方式加签
     *
     * @param task 需要被清空的任务
     */
    private void clearTaskScopeTypeAndSave(Task task) {
        TaskEntityImpl taskImpl = (TaskEntityImpl) task;
        taskImpl.setScopeType(null);
        taskService.saveTask(task);
    }

    /**
     * 获取子任务个数
     *
     * @param parentTaskId 父任务 ID
     * @return 剩余子任务个数
     */
    private Long getChildrenTaskCount(String parentTaskId) {
        String tableName = managementService.getTableName(TaskEntity.class);
        String sql = "SELECT COUNT(1) from " + tableName + " WHERE PARENT_TASK_ID_=#{parentTaskId}";
        return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count();
    }

    /**
     * 审批被委派的任务
     *
     * @param reqVO 前端请求参数，包含当前任务ID，审批意见等
     * @param task  当前被审批的任务
     */
    private void approveDelegateTask(BpmTaskApproveReqVO reqVO, Task task) {
        // 1. 添加审批意见
        AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId()).getCheckedData();
        AdminUserRespDTO sourceApproveUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())).getCheckedData();
        Assert.notNull(sourceApproveUser, "委派任务找不到原审批人，需要检查数据");
        String comment = StrUtil.format("[{}]完成委派任务，任务重新回到[{}]手中，审批意见为:{}", currentUser.getNickname(),
                sourceApproveUser.getNickname(), reqVO.getReason());
        taskService.addComment(reqVO.getId(), task.getProcessInstanceId(),
                BpmCommentTypeEnum.DELEGATE.getType().toString(), comment);

        // 2.1 调用 resolveTask 完成任务。
        // 底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner())：将 owner 设置为 assignee
        taskService.resolveTask(task.getId());
        // 2.2 更新任务拓展表为【处理中】
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())
                        .setReason(reqVO.getReason()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) {
        Task task = validateTask(userId, reqVO.getId());
        // 校验流程实例存在
        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
        if (instance == null) {
            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
        }

        // 更新流程实例为不通过
        processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason());

        // 更新任务拓展表为不通过
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult())
                        .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason()));
    }

    @Override
    public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) {
        // 校验任务存在
        Task task = validateTask(userId, reqVO.getId());
        // 更新负责人
        updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId());
    }

    @Override
    public void updateTaskAssignee(String id, Long userId) {
        taskService.setAssignee(id, String.valueOf(userId));
    }

    /**
     * 校验任务是否存在， 并且是否是分配给自己的任务
     *
     * @param userId 用户 id
     * @param taskId task id
     */
    private Task validateTask(Long userId, String taskId) {
        Task task = validateTaskExist(taskId);
        if (userId != null) {
            if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
                throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF);
            }
        }
        return task;
    }

    @Override
    public void createTaskExt(Task task) {
        BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
                .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
        // 向后加签生成的任务，状态不能为进行中，需要等前面父任务完成
        if (BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType().equals(task.getScopeType())) {
            taskExtDO.setResult(BpmProcessInstanceResultEnum.WAIT_BEFORE_TASK.getResult());
        }
        taskExtMapper.insert(taskExtDO);
    }

    @Override
    public void updateTaskExtComplete(Task task) {
        BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
                .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大，因为 Complete 一般是审核通过，已经设置
                .setEndTime(LocalDateTime.now());
        taskExtMapper.updateByTaskId(taskExtDO);
    }

    @Override
    public void updateTaskExtCancel(String taskId) {
        // 需要在事务提交后，才进行查询。不然查询不到历史的原因
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

            @Override
            public void afterCommit() {
                // 可能只是活动，不是任务，所以查询不到
                HistoricTaskInstance task = getHistoricTask(taskId);
                if (task == null) {
                    return;
                }

                // 如果任务拓展表已经是完成的状态，则跳过
                BpmTaskExtDO taskExt = taskExtMapper.selectByTaskId(taskId);
                if (taskExt == null) {
                    log.warn("[updateTaskExtCancel][taskId({}) 查找不到对应的记录，可能存在问题]", taskId);
                    return;
                }
                // 如果已经是最终的结果，则跳过
                if (BpmProcessInstanceResultEnum.isEndResult(taskExt.getResult())) {
                    log.info("[updateTaskExtCancel][taskId({}) 处于结果({})，无需进行更新]", taskId, taskExt.getResult());
                    return;
                }

                // 更新任务
                taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
                        .setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason())));
            }

        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTaskExtAssign(Task task) {

        BpmTaskExtDO taskExtDO =
                new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId());
        taskExtMapper.updateByTaskId(taskExtDO);

        // 发送通知。在事务提交时，批量执行操作，所以直接查询会无法查询到 ProcessInstance，所以这里是通过监听事务的提交来实现。
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

//            @Override
//            public void afterCommit() {
//
//                if (StrUtil.isNotEmpty(task.getAssignee())) {
//
//                    ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
//                    if (processInstance != null) {
//                        // 获得任务列表
//                        List<BpmTaskRespVO> BpmTaskRespVOs = getTaskListByProcessInstanceId(processInstance.getProcessInstanceId());
//                        AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())).getCheckedData();
//                        //发送信息通知
//                        messageService.sendMessageWhenTaskAssigned(
//                                BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task, BpmTaskRespVOs));
//                    }
//                }
//            }

            @Override
            public void afterCompletion(int status) {

                if(TransactionSynchronization.STATUS_COMMITTED == status){

                    BpmProcessInstanceExtDO processInstance = processInstanceService.getProcessInstanceDO(task.getProcessInstanceId());

                    // 判断不是加签状态的流程
                    if (task.getParentTaskId() != null) {

                        // 获取加签子任务的 父任务task
                        List<Task> childrenTasks = taskService.createTaskQuery().taskId(task.getParentTaskId()).orderByTaskCreateTime().desc().list();
                        if (CollUtil.isNotEmpty(childrenTasks) && childrenTasks.get(0).getScopeType().equals(BpmTaskAddSignTypeEnum.BEFORE.getType())) {
                            return;
                        }
                    }
                    if (task.getAssignee() == null) {
                        return;
                    }

                    // 如果当前审批人是流程发起人
                    // 则自动通过当前审批节点
                    if (processInstance.getStartUserId().toString().equals(task.getAssignee())) {

                        // 自动审核通过任务
                        autoApproveTask(task);
                        return;
                    } else {

                        // 判断当前审批人是否在该流程中 已通过审批，
                        // 如果有，则自动审批通过该审批人节点
                        Long count = taskExtMapper.selectListCount(Long.valueOf(task.getAssignee()), task.getProcessInstanceId());

                        if (count > 0L) {

                            // 自动审核通过任务
                            autoApproveTask(task);
                            return;
                        }
                    }

                    ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
                    if (instance != null) {
                        // 获得任务列表
                        List<BpmTaskRespVO> BpmTaskRespVOs = getTaskListByProcessInstanceId(instance.getProcessInstanceId());
                        AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData();
                        //发送信息通知
                        messageService.sendMessageWhenTaskAssigned(
                                BpmTaskConvert.INSTANCE.convert(instance, startUser, task, BpmTaskRespVOs));
                    }
                }
            }
        });
    }

    /**
     * 自动审核通过任务
     */
    private void autoApproveTask(Task task) {

        BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO();
        reqVO.setId(task.getId());
        reqVO.setReason(BpmConstants.AUTO_APPRAVAL);

        CountDownLatch countDownLatch = new CountDownLatch(1);
        // 另起线程处理 任务通过， 避免事务之间重复调用异常
        new Thread(() -> {
            try {
                approveTask(Long.valueOf(task.getAssignee()), reqVO) ;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 执行完毕，计数器减1
                countDownLatch.countDown();
            }
        }).start();
        try {
            countDownLatch.await(); // 等待直到计数器为0
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private Task validateTaskExist(String id) {
        Task task = getTask(id);
        if (task == null) {
            throw exception(TASK_NOT_EXISTS);
        }
        return task;
    }

    private Task getTask(String id) {
        return taskService.createTaskQuery().taskId(id).singleResult();
    }

    private HistoricTaskInstance getHistoricTask(String id) {
        return historyService.createHistoricTaskInstanceQuery().taskId(id).singleResult();
    }

    @Override
    public List<BpmTaskSimpleRespVO> getReturnTaskList(String taskId) {
        // 1. 校验当前任务 task 存在
        Task task = validateTaskExist(taskId);
        // 根据流程定义获取流程模型信息
        BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
        FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
        if (source == null) {
            throw exception(TASK_NOT_EXISTS);
        }

        // 2.1 查询该任务的前置任务节点的 key 集合
        List<UserTask> previousUserList = BpmnModelUtils.getPreviousUserTaskList(source, null, null);
        if (CollUtil.isEmpty(previousUserList)) {
            return Collections.emptyList();
        }
        // 2.2 过滤：只有串行可到达的节点，才可以回退。类似非串行、子流程无法退回
        previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null));
        return BpmTaskConvert.INSTANCE.convertList(previousUserList);
    }

    @Resource
    private BpmProcessDefinitionService processDefinitionService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void returnTask(Long userId, BpmTaskReturnReqVO reqVO) {
        // 1.1 当前任务 task
        Task task = validateTask(userId, reqVO.getId());
        if (task.isSuspended()) {
            throw exception(TASK_IS_PENDING);
        }
        // 1.2 校验源头和目标节点的关系，并返回目标元素
        FlowElement targetElement = validateTargetTaskCanReturn(task.getTaskDefinitionKey(), reqVO.getTargetDefinitionKey(), task.getProcessDefinitionId());

        // 2. 调用 flowable 框架的回退逻辑
        returnTask0(task, targetElement, reqVO);

        // 3. 更新任务扩展表
        taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
                .setResult(BpmProcessInstanceResultEnum.BACK.getResult())
                .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason()));
    }

    /**
     * 回退流程节点时，校验目标任务节点是否可回退
     *
     * @param sourceKey           当前任务节点 Key
     * @param targetKey           目标任务节点 key
     * @param processDefinitionId 当前流程定义 ID
     * @return 目标任务节点元素
     */
    private FlowElement validateTargetTaskCanReturn(String sourceKey, String targetKey, String processDefinitionId) {
        // 1.1 获取流程模型信息
        BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(processDefinitionId);
        // 1.3 获取当前任务节点元素
        FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, sourceKey);
        // 1.3 获取跳转的节点元素
        FlowElement target = BpmnModelUtils.getFlowElementById(bpmnModel, targetKey);
        if (target == null) {
            throw exception(TASK_TARGET_NODE_NOT_EXISTS);
        }

        // 2.2 只有串行可到达的节点，才可以回退。类似非串行、子流程无法退回
        if (!BpmnModelUtils.isSequentialReachable(source, target, null)) {
            throw exception(TASK_RETURN_FAIL_SOURCE_TARGET_ERROR);
        }
        return target;
    }

    /**
     * 执行回退逻辑
     *
     * @param currentTask   当前回退的任务
     * @param targetElement 需要回退到的目标任务
     * @param reqVO         前端参数封装
     */
    public void returnTask0(Task currentTask, FlowElement targetElement, BpmTaskReturnReqVO reqVO) {
        // 1. 获得所有需要回撤的任务 taskDefinitionKey，用于稍后的 moveActivityIdsToSingleActivityId 回撤
        // 1.1 获取所有正常进行的任务节点 Key
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(currentTask.getProcessInstanceId()).list();
        List<String> runTaskKeyList = convertList(taskList, Task::getTaskDefinitionKey);
        // 1.2 通过 targetElement 的出口连线，计算在 runTaskKeyList 有哪些 key 需要被撤回
        // 为什么不直接使用 runTaskKeyList 呢？因为可能存在多个审批分支，例如说：A -> B -> C 和 D -> F，而只要 C 撤回到 A，需要排除掉 F
        List<UserTask> returnUserTaskList = BpmnModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null);
        List<String> returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId);

        // 2. 给当前要被回退的 task 数组，设置回退意见
        taskList.forEach(task -> {
            // 需要排除掉，不需要设置回退意见的任务
            if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) {
                return;
            }
            taskService.addComment(task.getId(), currentTask.getProcessInstanceId(),
                    BpmCommentTypeEnum.BACK.getType().toString(), reqVO.getReason());
        });

        // 3. 执行驳回
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(currentTask.getProcessInstanceId())
                .moveActivityIdsToSingleActivityId(returnTaskKeyList, // 当前要跳转的节点列表( 1 或多)
                        reqVO.getTargetDefinitionKey()) // targetKey 跳转到的节点(1)
                .changeState();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delegateTask(Long userId, BpmTaskDelegateReqVO reqVO) {
        // 1.1 校验任务
        Task task = validateTaskCanDelegate(userId, reqVO);
        // 1.2 校验目标用户存在
        AdminUserRespDTO delegateUser = adminUserApi.getUser(reqVO.getDelegateUserId()).getCheckedData();
        if (delegateUser == null) {
            throw exception(TASK_DELEGATE_FAIL_USER_NOT_EXISTS);
        }

        // 2. 添加审批意见
        AdminUserRespDTO currentUser = adminUserApi.getUser(userId).getCheckedData();
        String comment = StrUtil.format("[{}]将任务委派给[{}]，委派理由为:{}", currentUser.getNickname(),
                delegateUser.getNickname(), reqVO.getReason());
        String taskId = reqVO.getId();
        taskService.addComment(taskId, task.getProcessInstanceId(),
                BpmCommentTypeEnum.DELEGATE.getType().toString(), comment);

        // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee)
        taskService.setOwner(taskId, task.getAssignee());
        // 3.2 执行委派，将任务委派给 receiveId
        taskService.delegateTask(taskId, reqVO.getDelegateUserId().toString());
        // 3.3 更新任务拓展表为【委派】
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.DELEGATE.getResult())
                        .setReason(reqVO.getReason()));
    }

    /**
     * 校验任务委派参数
     *
     * @param userId 用户编号
     * @param reqVO  任务编号，接收人ID
     * @return 当前任务信息
     */
    private Task validateTaskCanDelegate(Long userId, BpmTaskDelegateReqVO reqVO) {
        // 校验任务
        Task task = validateTask(userId, reqVO.getId());
        // 校验当前审批人和被委派人不是同一人
        if (task.getAssignee().equals(reqVO.getDelegateUserId().toString())) {
            throw exception(TASK_DELEGATE_FAIL_USER_REPEAT);
        }
        return task;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO) {
        // 1. 获取和校验任务
        TaskEntityImpl taskEntity = validateAddSign(userId, reqVO);
        List<AdminUserRespDTO> userList = adminUserApi.getUserList(reqVO.getUserIdList()).getCheckedData();
        if (CollUtil.isEmpty(userList)) {
            throw exception(TASK_ADD_SIGN_USER_NOT_EXIST);
        }

        // 2. 处理当前任务
        // 2.1 开启计数功能，主要用于为了让表 ACT_RU_TASK 中的 SUB_TASK_COUNT_ 字段记录下总共有多少子任务，后续可能有用
        taskEntity.setCountEnabled(true);
        if (reqVO.getType().equals(BpmTaskAddSignTypeEnum.BEFORE.getType())) {
            // 2.2 向前加签，设置 owner，置空 assign。等子任务都完成后，再调用 resolveTask 重新将 owner 设置为 assign
            // 原因是：不能和向前加签的子任务一起审批，需要等前面的子任务都完成才能审批
            taskEntity.setOwner(taskEntity.getAssignee());
            taskEntity.setAssignee(null);
            // 2.3 更新扩展表状态
            taskExtMapper.updateByTaskId(
                    new BpmTaskExtDO().setTaskId(taskEntity.getId())
                            .setResult(BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult())
                            .setReason(reqVO.getReason()));
        }
        // 2.4 记录加签方式，完成任务时需要用到判断
        taskEntity.setScopeType(reqVO.getType());
        // 2.5 保存当前任务修改后的值
        taskService.saveTask(taskEntity);

        // 3. 创建加签任务
        createSignTask(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity);

        // 4. 记录加签 comment，拼接结果为： [当前用户]向前加签/向后加签给了[多个用户]，理由为：reason
        AdminUserRespDTO currentUser = adminUserApi.getUser(userId).getCheckedData();
        String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), currentUser.getNickname(),
                BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason());
        taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(),
                BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment);
    }


    /**
     * 校验任务的加签是否一致
     * <p>
     * 1. 如果存在“向前加签”的任务，则不能“向后加签”
     * 2. 如果存在“向后加签”的任务，则不能“向前加签”
     *
     * @param userId 当前用户 ID
     * @param reqVO  请求参数，包含任务 ID 和加签类型
     * @return 当前任务
     */
    private TaskEntityImpl validateAddSign(Long userId, BpmTaskAddSignReqVO reqVO) {
        TaskEntityImpl taskEntity = (TaskEntityImpl) validateTask(userId, reqVO.getId());
        // 向前加签和向后加签不能同时存在
        if (StrUtil.isNotBlank(taskEntity.getScopeType())
                && ObjectUtil.notEqual(BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType(), taskEntity.getScopeType())
                && ObjectUtil.notEqual(taskEntity.getScopeType(), reqVO.getType())) {
            throw exception(TASK_ADD_SIGN_TYPE_ERROR,
                    BpmTaskAddSignTypeEnum.formatDesc(taskEntity.getScopeType()), BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()));
        }
        // 同一个 key 的任务，审批人不重复
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(taskEntity.getProcessInstanceId())
                .taskDefinitionKey(taskEntity.getTaskDefinitionKey()).list();
        List<Long> currentAssigneeList = convertList(taskList, task -> NumberUtils.parseLong(task.getAssignee()));
        // 保留交集在 currentAssigneeList 中
        currentAssigneeList.retainAll(reqVO.getUserIdList());
        if (CollUtil.isNotEmpty(currentAssigneeList)) {
            List<AdminUserRespDTO> userList = adminUserApi.getUserList(currentAssigneeList).getCheckedData();
            throw exception(TASK_ADD_SIGN_USER_REPEAT, String.join(",", convertList(userList, AdminUserRespDTO::getNickname)));
        }
        return taskEntity;
    }

    /**
     * 创建加签子任务
     *
     * @param addSingUserIdList 被加签的用户 ID
     * @param taskEntity        被加签的任务
     */
    private void createSignTask(List<String> addSingUserIdList, TaskEntityImpl taskEntity) {
        if (CollUtil.isEmpty(addSingUserIdList)) {
            return;
        }
        // 创建加签人的新任务，全部基于 taskEntity 为父任务来创建
        for (String addSignId : addSingUserIdList) {
            if (StrUtil.isBlank(addSignId)) {
                continue;
            }
            createSignTask(taskEntity, addSignId);
        }
    }

    /**
     * 创建加签子任务
     *
     * @param parentTask 父任务
     * @param assignee   子任务的执行人
     */
    private void createSignTask(TaskEntityImpl parentTask, String assignee) {
        // 1. 生成子任务
        TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID());
        task = BpmTaskConvert.INSTANCE.convert(task, parentTask);
        if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(parentTask.getScopeType())) {
            // 2.1 前加签，设置审批人
            task.setAssignee(assignee);
        } else {
            // 2.2.1 设置 owner 不设置 assignee 是因为不能同时审批，需要等父任务完成
            task.setOwner(assignee);
            // 2.2.2 设置向后加签任务的 scopeType 为 afterChildrenTask，用于设置任务扩展表的状态
            task.setScopeType(BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType());
        }
        // 2. 保存子任务
        taskService.saveTask(task);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO) {
        // 1.1 校验 task 可以被减签
        Task task = validateSubSign(reqVO.getId());
        // 1.2 校验取消人存在
        AdminUserRespDTO cancelUser = null;
        if (StrUtil.isNotBlank(task.getAssignee())) {
            cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee())).getCheckedData();
        }
        if (cancelUser == null && StrUtil.isNotBlank(task.getOwner())) {
            cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())).getCheckedData();
        }
        Assert.notNull(cancelUser, "任务中没有所有者和审批人，数据错误");

        // 2. 删除任务和对应子任务
        // 2.1 获取所有需要删除的任务 ID ，包含当前任务和所有子任务
        List<String> allTaskIdList = getAllChildTaskIds(task.getId());
        // 2.2 删除任务和所有子任务
        taskService.deleteTasks(allTaskIdList);
        // 2.3 修改扩展表状态为取消
        AdminUserRespDTO user = adminUserApi.getUser(userId).getCheckedData();
        taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
                .setReason(StrUtil.format("由于{}操作[减签]，任务被取消", user.getNickname())));

        // 3. 记录日志到父任务中。先记录日志是因为，通过 handleParentTask 方法之后，任务可能被完成了，并且不存在了，会报异常，所以先记录
        String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname());
        taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(),
                BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment);

        // 4. 处理当前任务的父任务
        handleParentTask(task);
    }

    /**
     * 校验任务是否能被减签
     *
     * @param id 任务ID
     * @return 任务信息
     */
    private Task validateSubSign(String id) {
        Task task = validateTaskExist(id);

        // 必须有 scopeType
        String scopeType = task.getScopeType();
        if (StrUtil.isEmpty(scopeType)) {
            throw exception(TASK_SUB_SIGN_NO_PARENT);
        }
        // 并且值为 向前和向后加签
        if (!validateSignType(scopeType)) {
            throw exception(TASK_SUB_SIGN_NO_PARENT);
        }
        return task;
    }

    /**
     * 判断当前类型是否为加签
     *
     * @param scopeType 任务的 scopeType
     * @return 当前 scopeType 为加签则返回 true
     */
    private boolean validateSignType(String scopeType) {
        return StrUtil.equalsAny(scopeType, BpmTaskAddSignTypeEnum.BEFORE.getType(), scopeType, BpmTaskAddSignTypeEnum.AFTER.getType());
    }

    /**
     * 获取所有要被取消的删除的任务 ID 集合
     *
     * @param parentTaskId 父级任务ID
     * @return 所有任务ID
     */
    public List<String> getAllChildTaskIds(String parentTaskId) {
        List<String> allChildTaskIds = new ArrayList<>();
        // 1. 递归获取子级
        Stack<String> stack = new Stack<>();
        // 1.1 将根任务ID入栈
        stack.push(parentTaskId);
        //控制遍历的次数不超过 Byte.MAX_VALUE，避免脏数据造成死循环
        int count = 0;
        // TODO @海：< 的前后空格，要注意哈；
        while (!stack.isEmpty() && count < Byte.MAX_VALUE) {
            // 1.2 弹出栈顶任务ID
            String taskId = stack.pop();
            // 1.3 将任务ID添加到结果集合中
            allChildTaskIds.add(taskId);
            // 1.4 获取该任务的子任务列表
            // TODO @海：有个更高效的写法；一次性去 in 一层；不然每个节点，都去查询一次 db， 太浪费了；每次 in，最终就是 O(h) 查询，而不是 O(n) 查询；
            List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);
            if (CollUtil.isNotEmpty(childrenTaskIdList)) {
                for (String childTaskId : childrenTaskIdList) {
                    // 1.5 将子任务ID入栈，以便后续处理
                    stack.push(childTaskId);
                }
            }
            count++;
        }
        return allChildTaskIds;
    }

    /**
     * 获取指定父级任务的所有子任务 ID 集合
     *
     * @param parentTaskId 父任务 ID
     * @return 所有子任务的 ID 集合
     */
    private List<String> getChildrenTaskIdList(String parentTaskId) {
        return convertList(getChildrenTaskList0(parentTaskId), Task::getId);
    }

    /**
     * 获取指定父级任务的所有子任务 ID 集合
     *
     * @param parentTaskId 父任务 ID
     * @return 所有子任务的 ID 集合
     */
    private List<Task> getChildrenTaskList0(String parentTaskId) {
        String tableName = managementService.getTableName(TaskEntity.class);
        // taskService.createTaskQuery() 没有 parentId 参数，所以写 sql 查询
        String sql = "select ID_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
        return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();
    }


    @Override
    public List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId) {
        // 1. 只查询进行中的任务 后加签的任务，可能不存在 assignee，所以还需要查询 owner
        List<Task> taskList = getChildrenTaskList0(parentId);
        if (CollUtil.isEmpty(taskList)) {
            return Collections.emptyList();
        }
        List<String> childrenTaskIdList = convertList(taskList, Task::getId);

        // 2.1 将 owner 和 assignee 统一到一个集合中
        List<Long> userIds = convertListByFlatMap(taskList, control ->
                Stream.of(NumberUtils.parseLong(control.getAssignee()), NumberUtils.parseLong(control.getOwner()))
                        .filter(Objects::nonNull));
        // 2.2 组装数据
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
        List<BpmTaskExtDO> taskExtList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList);
        Map<String, Task> idTaskMap = convertMap(taskList, TaskInfo::getId);
        return BpmTaskConvert.INSTANCE.convertList(taskExtList, userMap, idTaskMap);
    }


    @Override
    public String getCurrentTaskIdByProcessInstanceId(String processInstanceId) {
        TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(processInstanceId).active();
        List<Task> tasks = taskQuery.list();
        if (!tasks.isEmpty()) {
            Task currentTask = tasks.get(0);
//            System.out.println("当前任务节点ID: " + currentTask.getId());
//            System.out.println("当前任务节点名称: " + currentTask.getName());
//            System.out.println("当前任务节点创建时间: " + currentTask.getCreateTime());
//            System.out.println("当前任务节点分配给: " + currentTask.getAssignee());
            return currentTask.getId();
        } else {
            System.out.println("没有找到当前进行中的任务节点");
            throw exception(TASK_NOT_EXISTS);
        }
    }

    @Override
    public List<BpmTaskExtDO> getTaskByProcessInstanceIdAndResult(List<String> processInstanceId, Integer result) {

        return taskExtMapper.selectTask(processInstanceId, result);
    }

    @Override
    public BpmTaskExtDO getTaskByProcessInstanceIdAndResult(String processInstanceId, Integer result) {

        return taskExtMapper.selectOne(new LambdaQueryWrapperX<BpmTaskExtDO>()
                .eq(BpmTaskExtDO::getProcessInstanceId, processInstanceId)
                .eq(BpmTaskExtDO::getResult, result));
    }

    /**
     * 获取当前待处理流程实例（带查询条件），上一个流程和下一个流程的实例ID
     *
     * @param userId    用户编号
     * @param processInstanceId    流程实例id
     * @param pageVO 分页请求
     * @return 流程任务分页
     */
    @Override
    public Map<String,String> getCurrentToDoProcessInstacePreAndNex(Long userId, String processInstanceId,BpmTaskTodoPageReqVO pageVO) {
        pageVO.setPageSize(100);
        PageResult<BpmTaskTodoPageRespVO> list = getTodoTaskPage1(userId, pageVO) ;

        List<BpmTaskTodoPageRespVO> vos = list.getList() ;
        List<String> processInstanceIds = new ArrayList<>() ;
        for (BpmTaskTodoPageRespVO vo : vos) {
            processInstanceIds.add(vo.getProcessInstanceId()) ;
        }
        String pre = null ;
        String next = null ;
        Long total = list.getTotal() ;

        Integer pageNo = pageVO.getPageNo() ;
        //hasNext == true  还有下一页  false  没有下一页
        boolean hasNext = PageUtils.hasNextPage(total.intValue(),pageVO) ;
        //hasPre == true  还有下上页  false  没有上一页
        boolean hasPre = pageVO.getPageNo() > 1 ;
        //获取上一个
        for (int i = 0; i < processInstanceIds.size(); i++) {
            if(  processInstanceIds.get(i).equals(processInstanceId)  ) {
                if( i > 0 ) {
                    pre = processInstanceIds.get(i - 1) ;
                }else if( hasPre  ) {
                    pageVO.setPageNo(pageNo - 1);
                    list = getTodoTaskPage1(userId, pageVO) ;
                    BpmTaskTodoPageRespVO vo = list.getList().get(list.getList().size()-1);
                    pre = vo.getProcessDefinitionId() ;
                }else {
                    pre = null ;
                }
            }
        }
        //获取下一个
        for (int i = 0; i < processInstanceIds.size(); i++) {
            if(  processInstanceIds.get(i).equals(processInstanceId)  ) {
                if( i < processInstanceIds.size() - 1 ) {
                    next = processInstanceIds.get(i + 1) ;
                }else if( hasNext  ) {
                    pageVO.setPageNo(pageNo + 1);
                    list = getTodoTaskPage1(userId, pageVO) ;
                    BpmTaskTodoPageRespVO vo = list.getList().get(0);
                    next = vo.getProcessDefinitionId() ;
                }else {
                    next = null ;
                }
            }
        }



//        int index = processInstanceIds.indexOf(processInstanceId);
//        if(index == 0  ) {
//            //下标未0
//            if (pageNo == 1) {
//                //如果pageNo == 1  说明是第一页，第一条数据，那么就没有pre
//                log.info("没有上个");
//                pre = null;
//            } else {
//                //如果pageNo > 1  说明是不是第一页的第一条数据，那么就有pre
//                //设置当前页面-1，并查询数据
//                pageVO.setPageNo(pageNo - 1);
//                log.info("查询上一页");
//                list = getTodoTaskPage(userId, pageVO) ;
//                BpmTaskTodoPageItemRespVO vo = list.getList().get(list.getList().size()-1);
//                pre = vo.getProcessInstance().getId() ;
//            }
//            if( processInstanceIds.size() == 1  ) {
//                //说明这一页，只有一条数据，没有下一条了
//                log.info("没有下一个");
//                next = null ;
//            }else {
//                next = processInstanceIds.get(index + 1);
//            }
//        } else if( index == processInstanceIds.size() -1  ) {
//            //如果下标==数据集合的size-1，说明是当前页面的最后一条数据
//            pre = processInstanceIds.get(index - 1);
//            if(!hasNext) {
//                //如果没有下一页了
//                log.info("没有下一个");
//                next = null; ;
//            }else {
//                //正常下一条数据
//                //设置当前页面+1，并查询数据
//                pageVO.setPageNo(pageNo + 1);
//                log.info("查询下一页");
//                list = getTodoTaskPage(userId, pageVO) ;
//                BpmTaskTodoPageItemRespVO vo = list.getList().get(0);
//                next = vo.getProcessInstance().getId() ;
//
//                //审批处理后的下一条数据， 因为处理的是当前页最后一条数据，假设10条数据，处理了一条变成9条，重新查询后，会把原来第二页的数据查询在第一页的来。
//                //所有重新查询当前页面后，取最后一条数据
//                /**
//                log.info("审批后重新查询");
//                list = getTodoTaskPage(userId, pageVO) ;
//                BpmTaskTodoPageItemRespVO vo1 = list.getList().get(processInstanceIds.size() -1);
//                next = vo1.getProcessInstance().getId() ;
//                **/
//            }
//
//        }else if( index > 0 && index < processInstanceIds.size() ){
//            //如果下标大于0 且不等于processInstanceIds.size()  ，说明是中间的数据
//            pre = processInstanceIds.get(index - 1);
//            next = processInstanceIds.get(index + 1);
//        }else {
//            log.info("传入的processInstanceId:"+processInstanceId+"在列表中不存在");
//            pre = null ;
//            next = null ;
//        }

        Map<String,String> map = new HashMap<>() ;
        map.put("pre",pre) ;
        map.put("next",next);
        map.put("current",processInstanceId) ;
        map.put("total",total.toString()) ;
        map.put("currentPage",pageVO.getPageNo().toString()) ;
        return map ;
    }

    @Override
    public List<Long> getTodoTaskDept(BpmTaskTodoPageReqVO pageVO, Long userId) {

        return taskExtMapper.selectTodoTaskDept(pageVO, userId);
    }

    @Override
    public PageResult<BpmTaskExtDO> getCrmTask(Long userId, BpmCrmTaskPageReqVO pageReqVO) {

        return taskExtMapper.selectCrmPage(userId, pageReqVO);
    }
}

