package com.sunxung.factoring.service.sys.flowable.impl;

import com.sunxung.factoring.component.exception.BusinessException;
import com.sunxung.factoring.component.exception.ValidatorException;
import com.sunxung.factoring.component.util.*;
import com.sunxung.factoring.entity.GridPage;
import com.sunxung.factoring.entity.financing.apply.CFinancingBasicInfo;
import com.sunxung.factoring.entity.project.BusinessProcessingLog;
import com.sunxung.factoring.entity.project.Project;
import com.sunxung.factoring.entity.project.vo.SearchBusinessProcessingTask;
import com.sunxung.factoring.entity.sys.FileStorage;
import com.sunxung.factoring.entity.sys.User;
import com.sunxung.factoring.entity.sys.flowable.FlowActivityDefinition;
import com.sunxung.factoring.entity.sys.flowable.request.DeployRequest;
import com.sunxung.factoring.entity.sys.flowable.vo.ProcessDefinitionEntityVo;
import com.sunxung.factoring.entity.sys.flowable.vo.SearchProcessDefinition;
import com.sunxung.factoring.mapper.sys.flowable.FlowActivityDefinitionMapper;
import com.sunxung.factoring.service.project.BusinessProcessingLogService;
import com.sunxung.factoring.service.sys.FileStorageService;
import com.sunxung.factoring.service.sys.UserService;
import com.sunxung.factoring.service.sys.flowable.FlowActivityDefinitionService;
import com.sunxung.factoring.service.sys.flowable.FlowableService;
import com.sunxung.factoring.service.sys.systemMsg.SystemMsgService;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.NativeTaskQuery;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.zip.ZipInputStream;

@Service
public class FlowableServiceImpl implements FlowableService {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private FlowActivityDefinitionService flowActDefService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private FormService formService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private BusinessProcessingLogService processingLogService;
    @Autowired
    private UserService userService;
    @Autowired
    private SystemMsgService sysMsgService;
    @Autowired
    private FlowActivityDefinitionMapper flowActivityDefinitionMapper;
    @Autowired
    private FileStorageService fileStorageService;

    @Override
    public GridPage<ProcessDefinitionEntityVo> findLatestProcdef(SearchProcessDefinition search) {
        if (null == search) {
            throw new ValidatorException(CodeUtil.FAIL, "列表分页条件不能为空！");
        }
        List<ProcessDefinition> procdefList = repositoryService.createProcessDefinitionQuery()
                .listPage((search.getPage() - 1) * search.getRows(), search.getPage() * search.getRows());
        Map<String, ProcessDefinition> filterMap = new HashMap<>();
        if (null != procdefList && procdefList.size() > 0) {
            for (ProcessDefinition pd : procdefList) {
                filterMap.put(pd.getId(), pd);
            }
        }
        List<ProcessDefinitionEntityVo> rows = new ArrayList<>();
        for (ProcessDefinition pd : filterMap.values()) {
            rows.add(new ProcessDefinitionEntityVo(pd));
        }
        long count = repositoryService.createProcessDefinitionQuery().count();
        return new GridPage<>(search.getRows(), search.getPage(), count, rows);
    }

    @Override
    @Transactional
    public Deployment deploy(DeployRequest deployRequest) {
        FileStorage fileStorage = fileStorageService.get(deployRequest.getId());
        if(fileStorage==null){
            throw new BusinessException(CodeUtil.FAIL,"部署文件不能为空");
        }
        ZipInputStream zipIn = null;
        try {
            FileInputStream fileInputStream = new FileInputStream(fileStorage.getAbsolutePath());
            zipIn = new ZipInputStream(fileInputStream);
        } catch (Exception e) {
            throw new BusinessException(CodeUtil.FAIL, e.getMessage());
        }
        Deployment deployment = repositoryService.createDeployment().name(deployRequest.getDeployName()).addZipInputStream(zipIn).deploy();
        if (null != deployment) {
            // 部署结束后，还需要根据流程定义key、版本、id过滤，后台设置流程节点，区别是否允许设置之前版本的节点办理人问题
            ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                    .deploymentId(deployment.getId()).singleResult();
            if (null != procDef) {
                BpmnModel model = repositoryService.getBpmnModel(procDef.getId());
                if (model != null) {
                    Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
                    for (FlowElement e : flowElements) {
                        if (e instanceof UserTask) {// 过滤用户任务
                            FlowActivityDefinition flowActDef = new FlowActivityDefinition();
                            flowActDef.setProcessDefinitionId(procDef.getId());
                            flowActDef.setProcessDefinitionKey(procDef.getKey());
                            flowActDef.setProcessDefinitionVersion(procDef.getVersion());
                            flowActDef.setActivityKey(e.getId());
                            flowActDef.setActivityName(e.getName());
                            flowActDef.setActivityType(ConstantUtil.FLOWABLE_ACTTYPE_USERTASK);
                            flowActDefService.add(flowActDef);
                            System.out.println("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:"
                                    + e.getClass().toString());
                        }
                    }
                }
            }
        }
        return deployment;
    }

    @Override
    public void viewImg(HttpServletResponse response, String deploymentId, String resourceName) {
        InputStream input = repositoryService.getResourceAsStream(deploymentId, resourceName);
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            byte[] b = new byte[1024];
            int len = -1;
            while ((len = input.read(b)) != -1) {
                out.write(b, 0, len);
            }
            out.close();
            input.close();
        } catch (IOException e) {
            throw new BusinessException(CodeUtil.FAIL, e.getMessage());
        }
    }

    @Override
    @Transactional
    public ProcessInstance startProcessInstance(Project entity, Map<String, Object> procVariables, String queryBusiness,
                                                Map<String, Object> msgVariables, String key) {
        if (null == entity || null == entity.getId()) {
            throw new ValidatorException(CodeUtil.FAIL, "流程业务实体信息不能为空！");
        }
        if (null == procVariables || procVariables.isEmpty()) {
            throw new ValidatorException(CodeUtil.FAIL, "流程变量map不能为空！");
        }
        if (StringUtils.isEmpty(queryBusiness)) {
            throw new ValidatorException(CodeUtil.FAIL, "流程businessKey信息不能为空！");
        }
        /**
         * String objId = FlowableUtil.generateBusinessKey(entity,queryBusiness);
         * 将objId结果作为queryBusiness参数传入，便于可扩展的需求<br>
         * 如PaymentApplyBasic，businessKey需要为PaymentInfo信息，而不是PaymentApplyBasic.
         */
        // 1.开启流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceByKey(key, queryBusiness, procVariables);
        if (null != procInst && StringUtils.isNotEmpty(procInst.getId())) {
            List<Task> pendingTasks = taskService.createTaskQuery().processInstanceId(procInst.getId()).list();
            if (null != pendingTasks && pendingTasks.size() > 0) {
                for (Task task : pendingTasks) {

                    BusinessProcessingLog processingLog = new BusinessProcessingLog();
                    if (task.getAssignee() != null) {
                        Long assignee = Long.parseLong(task.getAssignee());
                        processingLog.setAssignee(userService.get(assignee));
                    }
                    // 2.添加业务处理日志
                    processingLog.setBusnessKey(entity.getId());
                    processingLog.setBusinessType(key);
                    processingLog.setHistoricTaskId(task.getId());
                    processingLog.setAssigneeType(ConstantConversionUtil.PROCESS_TASK);
                    processingLog.setTaskDefKey(task.getTaskDefinitionKey());
                    processingLog.setTaskName(task.getName());
                    processingLog.setStartTime(task.getCreateTime());
                    processingLogService.add(processingLog);
                    // 3.新增直属上级可分配的任务，如付款申请及审批业务流程，分配需要单独处理，故过滤掉
                    // 4.发送系统待办消息：执行者消息可链接跳转处理信息，知晓者不可以。知晓者只有流出时才发消息，故开启流程实例时不存在知晓者消息。
                    if (msgVariables != null && msgVariables.size() > 0) {
//                        sysMsgService.sendFlowMsgImmediately((String) msgVariables.get(ConstantUtil.FLOWABLE_MSG_TITLE),
//                                ((String) msgVariables.get(ConstantUtil.FLOWABLE_MSG_CONTENT)).replace("formBusiness",
//                                        task.getName()),
//                                Arrays.asList(assignee), entity.getId(),
//                                ConstantConversionUtil.flowBusinessModuleCodes.get(key), true,
//                                task.getId());
                    }
                }
            }
        }
        return procInst;
    }

    @Override
    public List<Task> findMyPendingListPage(SearchBusinessProcessingTask search, String procDefinitionKey) {
        // procDefinitionKey：由于业务流程比较多，可能存在不同业务上的待我办任务，故查询时，就要结合业务KEY，查询具体业务上的“我的任务”
        if (null == search || StringUtils.isEmpty(procDefinitionKey)) {
            throw new ValidatorException(CodeUtil.FAIL, "列表分页条件不能为空！");
        }
        // 直接分配给当前人或者已签收的任务，银科业务系统目前是直接办理人，故暂时这么coding
        List<Task> doingTasks;
        if (StringUtils.isNotEmpty(search.getTaskId())) {
            // 系统待办消息跳转查询指定taskId的任务
            doingTasks = taskService.createTaskQuery().taskId(search.getTaskId()).list();
        } else {
            NativeTaskQuery nativeTaskQuery;
            String userId = ThreadLocalUtil.getUserId().toString();
            if (procDefinitionKey.startsWith("FinancialCustomer")) {
                nativeTaskQuery = taskService.createNativeTaskQuery()
                        .parameter("assignee", userId)
                        .parameter("procDefinitionKey", procDefinitionKey);
            } else {
                nativeTaskQuery = taskService.createNativeTaskQuery()
                        .parameter("assignee", userId)
                        .parameter("procDefinitionKey", procDefinitionKey + "%");
            }
            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append("SELECT DISTINCT RES.* FROM ACT_RU_TASK RES " +
                    "LEFT JOIN ACT_RU_IDENTITYLINK I ON I.TASK_ID_ = RES.ID_ " +
                    "INNER JOIN ACT_RE_PROCDEF D ON RES.PROC_DEF_ID_ = D.ID_ " +
                    "INNER JOIN ACT_RU_EXECUTION E ON RES.PROC_INST_ID_ = E.ID_ WHERE " +
                    "D.KEY_ LIKE #{procDefinitionKey}" + "AND (" +
                    "RES.ASSIGNEE_ = #{assignee} OR (RES.ASSIGNEE_ IS NULL AND I.TYPE_ = 'candidate' AND ( I.USER_ID_ = #{assignee} )))");
            if (StringUtils.isNotEmpty(search.getFastSearch())) {
                stringBuffer.append("AND E.BUSINESS_KEY_ LIKE #{fastSearch} ");
                nativeTaskQuery.parameter("fastSearch", "%" + search.getFastSearch() + "%");
            }
            if (search.getStartDate() != null) {
                stringBuffer.append("AND DATE(RES.CREATE_TIME_) >= DATE(#{startDate}) ");
                nativeTaskQuery.parameter("startDate", search.getStartDate());
            }
            if (search.getEndDate() != null) {
                stringBuffer.append("AND DATE(RES.CREATE_TIME_) <= DATE(#{endDate}) ");
                nativeTaskQuery.parameter("endDate", search.getEndDate());
            }
            stringBuffer.append("ORDER BY RES.CREATE_TIME_ DESC ");
            doingTasks = nativeTaskQuery.sql(stringBuffer.toString()).listPage((search.getPage() - 1) * search.getRows(), search.getPage() * search.getRows());
        }
        // 多种实现方式，5.16之后版本提供如下简化查询方式，查询
        // doingTasks =
        // taskService.createTaskQuery().taskCandidateOrAssigned(ThreadLocalUtil.getUserId().toString()).list();
        return doingTasks;
    }

    @Override
    public long countMyPendingListPage(SearchBusinessProcessingTask search, String procDefinitionKey) {
        if (null == search || StringUtils.isEmpty(procDefinitionKey)) {
            throw new ValidatorException(CodeUtil.FAIL, "列表分页条件不能为空！");
        }
        long count;
        if (StringUtils.isNotEmpty(search.getTaskId())) {
            count = taskService.createTaskQuery().taskId(search.getTaskId()).count();
        } else {
            NativeTaskQuery nativeTaskQuery;
            if (procDefinitionKey.startsWith("FinancialCustomer")) {
                nativeTaskQuery = taskService.createNativeTaskQuery()
                        .parameter("assignee", ThreadLocalUtil.getUserId().toString())
                        .parameter("procDefinitionKey", procDefinitionKey);
            } else {
                nativeTaskQuery = taskService.createNativeTaskQuery()
                        .parameter("assignee", ThreadLocalUtil.getUserId().toString())
                        .parameter("procDefinitionKey", procDefinitionKey + "%");
            }
            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append("SELECT COUNT(*) FROM ACT_RU_TASK RES " +
                    "LEFT JOIN ACT_RU_IDENTITYLINK I ON I.TASK_ID_ = RES.ID_ AND I.USER_ID_ = #{assignee} " +
                    "INNER JOIN ACT_RE_PROCDEF D ON RES.PROC_DEF_ID_ = D.ID_ " +
                    "INNER JOIN ACT_RU_EXECUTION E ON RES.PROC_INST_ID_ = E.ID_ WHERE " +
                    "D.KEY_ LIKE #{procDefinitionKey}" + "AND (" +
                    "RES.ASSIGNEE_ = #{assignee} OR (RES.ASSIGNEE_ IS NULL AND I.TYPE_ = 'candidate' AND ( I.USER_ID_ = #{assignee} )))");
            if (StringUtils.isNotEmpty(search.getFastSearch())) {
                stringBuffer.append("AND E.BUSINESS_KEY_ LIKE #{fastSearch} ");
                nativeTaskQuery.parameter("fastSearch", "%" + search.getFastSearch() + "%");
            }
            if (search.getStartDate() != null) {
                stringBuffer.append("AND DATE(RES.CREATE_TIME_) >= DATE(#{startDate}) ");
                nativeTaskQuery.parameter("startDate", search.getStartDate());
            }
            if (search.getEndDate() != null) {
                stringBuffer.append("AND DATE(RES.CREATE_TIME_) <= DATE(#{endDate}) ");
                nativeTaskQuery.parameter("endDate", search.getEndDate());
            }
            count = nativeTaskQuery.sql(stringBuffer.toString()).count();
        }
        return count;
    }

    @Override
    public List<HistoricTaskInstance> findMyCompletedListPage(SearchBusinessProcessingTask search,
                                                              String processDefinitionKey) {
        if (null == search || StringUtils.isEmpty(processDefinitionKey)) {
            throw new ValidatorException(CodeUtil.FAIL, "列表分页条件不能为空！");
        }
        List<HistoricTaskInstance> historicTasks = null;// finsihed()表示已办理完
        if (StringUtils.isNotEmpty(search.getSourceBusinessId())) {
            if (StringUtils.isNotEmpty(search.getFastSearch())) {
                historicTasks = historyService.createHistoricTaskInstanceQuery().finished()
                        .taskAssignee(ThreadLocalUtil.getUserId().toString()).processDefinitionKey(processDefinitionKey)
                        .processInstanceBusinessKeyLike(search.getSourceBusinessId() + "%")
                        .processInstanceBusinessKeyLike("%" + search.getFastSearch() + "%")
                        .listPage((search.getPage() - 1) * search.getRows(), search.getPage() * search.getRows());
            } else {
                historicTasks = historyService.createHistoricTaskInstanceQuery().finished()
                        .taskAssignee(ThreadLocalUtil.getUserId().toString()).processDefinitionKey(processDefinitionKey)
                        .processInstanceBusinessKeyLike(search.getSourceBusinessId() + "%")
                        .listPage((search.getPage() - 1) * search.getRows(), search.getPage() * search.getRows());
            }
        } else {
            if (StringUtils.isNotEmpty(search.getFastSearch())) {
                historicTasks = historyService.createHistoricTaskInstanceQuery().finished()
                        .taskAssignee(ThreadLocalUtil.getUserId().toString()).processDefinitionKey(processDefinitionKey)
                        .processInstanceBusinessKeyLike("%" + search.getFastSearch() + "%")
                        .listPage((search.getPage() - 1) * search.getRows(), search.getPage() * search.getRows());
            } else {
                historicTasks = historyService.createHistoricTaskInstanceQuery().finished()
                        .taskAssignee(ThreadLocalUtil.getUserId().toString()).processDefinitionKey(processDefinitionKey)
                        .listPage((search.getPage() - 1) * search.getRows(), search.getPage() * search.getRows());
            }
        }
        return historicTasks;
    }

    @Override
    public long countMyCompletedListPage(SearchBusinessProcessingTask search, String procDefinitionKey) {
        if (null == search || StringUtils.isEmpty(procDefinitionKey)) {
            throw new ValidatorException(CodeUtil.FAIL, "列表分页条件不能为空！");
        }
        long count = 0L;// finsihed()表示已办理完
        if (StringUtils.isNotEmpty(search.getSourceBusinessId())) {
            if (StringUtils.isNotEmpty(search.getFastSearch())) {
                count = historyService.createHistoricTaskInstanceQuery().finished()
                        .taskAssignee(ThreadLocalUtil.getUserId().toString()).processDefinitionKey(procDefinitionKey)
                        .processInstanceBusinessKeyLike(search.getSourceBusinessId() + "%")
                        .processInstanceBusinessKeyLike("%" + search.getFastSearch() + "%").count();
            } else {
                count = historyService.createHistoricTaskInstanceQuery().finished()
                        .taskAssignee(ThreadLocalUtil.getUserId().toString()).processDefinitionKey(procDefinitionKey)
                        .processInstanceBusinessKeyLike(search.getSourceBusinessId() + "%").count();
            }
        } else {
            if (StringUtils.isNotEmpty(search.getFastSearch())) {
                count = historyService.createHistoricTaskInstanceQuery().finished()
                        .taskAssignee(ThreadLocalUtil.getUserId().toString()).processDefinitionKey(procDefinitionKey)
                        .processInstanceBusinessKeyLike("%" + search.getFastSearch() + "%").count();
            } else {
                count = historyService.createHistoricTaskInstanceQuery().finished()
                        .taskAssignee(ThreadLocalUtil.getUserId().toString()).processDefinitionKey(procDefinitionKey)
                        .count();
            }
        }
        return count;
    }

    @Override
    public Object getBusinessDataByProcessInst(String processInstId) {
        // 1.根据流程实例ID查询正在执行的对象表，返回流程实例对象
        ProcessInstance procInst = null;
        if (StringUtils.isNotEmpty(processInstId)) {
            procInst = runtimeService.createProcessInstanceQuery().processInstanceId(processInstId).singleResult();
        }
        // 2.根据流程实例关联的业务key，查询业务数据信息
        if (null != procInst) {
            String businessKey = procInst.getBusinessKey();
            return FlowableUtil.getBusinessDateById(businessKey);
        }
        return null;
    }

    @Override
    public Task getByTaskQuery(String taskId) {
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }

    @Override
    public boolean duplicateAssigneeByTaskQuery(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        // 若task为null，可能任务已经完成
        if (task == null || StringUtils.isEmpty(task.getAssignee())) { // 该任务已经完成
            return false;
        }
        if (task.getAssignee().equals(ThreadLocalUtil.getUserId().toString())) {
            return true;
        }
        return false;
    }

    @Override
    public HistoricTaskInstance getHistoricByTaskId(String taskId) {
        return historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
    }

    @Override
    public List<Task> findRuntimeTaskByProcessInstId(String processInstId) {
        return taskService.createTaskQuery().processInstanceId(processInstId).list();
    }

    @Override
    public ProcessInstance getRuntimeProcessInstById(String processInstId) {
        return runtimeService.createProcessInstanceQuery().processInstanceId(processInstId).singleResult();
    }

    @Override
    public HistoricProcessInstance getHistoricProcessInstById(String processInstId) {
        return historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstId).singleResult();
    }

    @Override
    public ProcessInstance getRuntimeProcessInstByBusinessKey(String processDefKey, String processInstBusinessKey) {
        return runtimeService.createProcessInstanceQuery().processDefinitionKey(processDefKey)
                .processInstanceBusinessKey(processInstBusinessKey).singleResult();
    }

    @Override
    public HistoricProcessInstance getHistoricProcessInstByBusinessKey(String processDefKey,
                                                                       String processInstBusinessKey) {
        return historyService.createHistoricProcessInstanceQuery().processDefinitionKey(processDefKey)
                .processInstanceBusinessKey(processInstBusinessKey).singleResult();
    }

    @Override
    @Transactional
    public Boolean assignManager(Task assignableTask, Long assignee) {
        // 1.验证任务是否完成或者结束
        if (null == assignableTask) {
            throw new ValidatorException(CodeUtil.FAIL, "业务已完成，无法进行分配！");
        }
        if (StringUtils.isNotEmpty(assignableTask.getAssignee()) && null != assignee) {
            // 2.验证办理人是否重合
            if (assignableTask.getAssignee().equals(assignee.toString())) {
                throw new ValidatorException(CodeUtil.FAIL, "所选用户即为此业务跟进执行人，请重选！");
            }
            // 3.分配
            taskService.setAssignee(assignableTask.getId(), assignee.toString());
            // 4.设置流程变量
            // 说明:setVariable针对流程实例(ACT_HI_VARINST表TASK_ID_字段为null),即相同流程变量名，后一次的值会替换之前的，setVariableLocal仅针对指定taskId有效.
            taskService.setVariable(assignableTask.getId(),
                    assignableTask.getTaskDefinitionKey() + ConstantUtil.ASSIGNEE, assignee);// 注意：要求与业务中设置流程变量类型一致，字符串的为字符串，数值类型为数值类型。
            // 5.验证分配是否成功
            Task after = taskService.createTaskQuery().taskId(assignableTask.getId()).singleResult();
            if (null != after && StringUtils.isNotEmpty(after.getAssignee())
                    && after.getAssignee().equals(assignee.toString())) {
                return true;
            }
        }
        return null;
    }

    @Override
    public String getTaskFormKeyByTaskId(String taskId, Long businessKey) {
        String url = formService.getTaskFormData(taskId).getFormKey();
        if (StringUtils.isNotEmpty(url)) {
            url += "?taskId=" + taskId;
            if (null != businessKey) {
                url += "&businessKey=" + businessKey;
            }
            return url;
        }
        return null;
    }

    @Override
    @Transactional
    public Boolean completeMyTask(String taskId, Project entity, Map<String, Object> procVariables, String result,
                                  Long formBusinessId, Map<String, Object> msgVariables, String key) {
        if (StringUtils.isEmpty(taskId)) {
            throw new ValidatorException(CodeUtil.FAIL, "任务ID为空");
        }
        if (entity == null || entity.getId() == null) {
            throw new ValidatorException(CodeUtil.FAIL, "流程业务ID为空");
        }
        if (formBusinessId == null) {
            throw new ValidatorException(CodeUtil.FAIL, "流程表单业务ID为空");
        }

        // 查看处理人最新的日志
        BusinessProcessingLog log = processingLogService.getLatestByTask(entity.getId(),
                key, taskId, ConstantConversionUtil.PROCESS_TASK);
        if(log == null && key.equals(ConstantUtil.BILL_BASIC_INFORMATION)){
            log = processingLogService.getLatestByTask(entity.getId(),
                    ConstantUtil.BILL_UNIT_PRICE_ADJUST, taskId, ConstantConversionUtil.PROCESS_TASK);
        }
        if (log == null) {
            throw new ValidatorException(CodeUtil.FAIL, "数据错误，处理人业务日志信息为空！");
        }
        String procInstId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
        if (null == procVariables) {
            procVariables = new HashMap<>();
        }
        if (StringUtils.isNotEmpty(result)) {
            procVariables.put("result", result);
        } else {
            result = "提交";// 默认状态提交，不保存到流程变量中，记入业务处理日志状态中
        }
        Task processingtask = getByTaskQuery(taskId);
        String title = (String) msgVariables.get(ConstantUtil.FLOWABLE_MSG_TITLE);
        String content = (String) msgVariables.get(ConstantUtil.FLOWABLE_MSG_CONTENT);
        String businessType = ConstantConversionUtil.flowBusinessModuleCodes.get(key);
        if (null != processingtask) {
            if (!processingtask.getAssignee().equals(ThreadLocalUtil.getUserId().toString())) {
                throw new ValidatorException(CodeUtil.FAIL, "提交失败，您并不是该业务处理人！");
            }
            FlowActivityDefinition flowActDef = flowActDefService
                    .getByProcActKey(processingtask.getProcessDefinitionId(), processingtask.getTaskDefinitionKey());
            if (StringUtils.isNotEmpty(log.getTaskDefKey())) {
                log.setStatus(result);
                log.setEndTime(new Date());
                Float overdue = null;
                if (flowActDef.getWorkingDay()) {
                    overdue = FlowableUtil.getBusinessDeadlineByWorkingDay(log.getGmtCreate(),
                            flowActDef.getTimeLimit(), flowActDef.getWorkingDay());
                } else {
                    overdue = FlowableUtil.getBusinessOverdueByNatureDay(log.getGmtCreate(), flowActDef.getTimeLimit());
                }
                if (null != formBusinessId) {
                    log.setFormBusinessId(formBusinessId);
                }
                if (null != overdue && overdue < 0) {// 只展示逾期，故直接转换为正数
                    log.setOverdueDays(Math.abs(overdue));
                    log.setWorkingDay(flowActDef.getWorkingDay());
                }
                log.setEndTime(new Date());
                // 完成当前任务
                taskService.complete(taskId, procVariables);
                // 更新业务处理日志
                processingLogService.update(log);
                // 删除对应的可分配任务
                @SuppressWarnings("unchecked")
                List<Long> knowerList = (List<Long>) msgVariables
                        .get(processingtask.getTaskDefinitionKey() + ConstantUtil.KNOWERLIST);
                // 不可链接跳转处理信息，若knowerList为null或空，表示无知晓者
                if (null != knowerList && knowerList.size() > 0 && StringUtils.isNotEmpty(content)) {
                    if (processingtask.getTaskDefinitionKey().equals(ConstantUtil.REVIEW_MEETING_REVIEWPREPARE)) {// 特殊消息处理
                        sysMsgService.sendFlowMsgImmediately(title,
                                (String) msgVariables.get(processingtask.getTaskDefinitionKey()), knowerList,
                                entity.getId(), businessType, false, null);
                    } else {
                        sysMsgService.sendFlowMsgImmediately(title,
                                content.replace("inOut", "流出").replace("formBusiness", processingtask.getName())
                                        + ConstantUtil.FLOWABLE_MSG_KNOWER,
                                knowerList, entity.getId(), businessType, false, null);
                    }
                }
            }
        }
        // 判断是否结束，更新业务数据状态
        ProcessInstance procInst = runtimeService.createProcessInstanceQuery().processInstanceId(procInstId)
                .singleResult();
        boolean endFlag = false;
        boolean errorEndFlag = false;
        // 1.当前节点为最后一个节点，故办理完任务后，流程实例结束
        if (null == procInst || StringUtils.isEmpty(procInst.getId())) {
            endFlag = true;
            return true;
        } else {
            List<Task> pendingTasks = taskService.createTaskQuery().processInstanceId(procInst.getId()).list();
            if (null != pendingTasks && pendingTasks.size() > 0) {
                for (Task task : pendingTasks) {
                    // 流程业务待处理任务日志集合，注：一定要在循环内，同时过滤正在新增过的日志
                    List<String> pendingTaskIds = processingLogService.findPendingTaskByBusiness(entity.getId(), key);
                    // a.过滤掉已存在的并列或会签任务节点的日志信息
                    if (null != pendingTaskIds && pendingTaskIds.size() > 0 && pendingTaskIds.contains(task.getId())) {
                        continue;
                    }
                    // 任务办理人
                    // b.添加业务处理日志
                    BusinessProcessingLog processingLog = new BusinessProcessingLog();
                    processingLog.setBusnessKey(entity.getId());
                    processingLog.setBusinessType(key);
                    processingLog.setHistoricTaskId(task.getId());
                    User assignee = userService.get(Long.parseLong(task.getAssignee())) == null?userService.get(1L):userService.get(Long.parseLong(task.getAssignee())) ;
                    if (task.getAssignee() != null) {
                        processingLog.setAssignee(assignee);
                    }
                    processingLog.setAssigneeType(ConstantConversionUtil.PROCESS_TASK);
                    processingLog.setTaskDefKey(task.getTaskDefinitionKey());
                    processingLog.setTaskName(task.getName());
                    processingLog.setStartTime(task.getCreateTime());
                    processingLogService.add(processingLog);
                    // d.发送系统待办消息：执行者消息可链接跳转处理信息，知晓者不可以。
                    sysMsgService.sendFlowMsgImmediately(title,
                            content.replace("inOut", "进入").replace("formBusiness", task.getName())
                                    + ConstantUtil.FLOWABLE_MSG_ASSIGNEE,
                            Arrays.asList(assignee.getId()), entity.getId(), businessType, true, task.getId());
                }
                return true;
            } else {
                // 2.若当前节点不是最后一个节点，但办理条件，并不流转到下一个节点，这时候需要主动结束流程实例
                runtimeService.deleteProcessInstance(procInstId, result);
                errorEndFlag = true;
            }
        }
        // 空结束或终止（否决）结束事件
        // 异常结束事件
        if (errorEndFlag) {
            /**
             *
             */
        }
        return false;
    }

    @Override
    @Transactional
    public Boolean completeMyTaskCustomer(String taskId, Project entity, Map<String, Object> procVariables, String result,
                                  Long formBusinessId, Map<String, Object> msgVariables, String key, Long assigneeId ) {
        if (StringUtils.isEmpty(taskId)) {
            throw new ValidatorException(CodeUtil.FAIL, "任务ID为空");
        }
        if (entity == null || entity.getId() == null) {
            throw new ValidatorException(CodeUtil.FAIL, "流程业务ID为空");
        }
        if (formBusinessId == null) {
            throw new ValidatorException(CodeUtil.FAIL, "流程表单业务ID为空");
        }

        // 查看处理人最新的日志
        BusinessProcessingLog log = processingLogService.getLatestByTask(entity.getId(),
                key, taskId, ConstantConversionUtil.PROCESS_TASK);
        if(log == null && key.equals(ConstantUtil.BILL_BASIC_INFORMATION)){
            log = processingLogService.getLatestByTask(entity.getId(),
                    ConstantUtil.BILL_UNIT_PRICE_ADJUST, taskId, ConstantConversionUtil.PROCESS_TASK);
        }
        if (log == null) {
            throw new ValidatorException(CodeUtil.FAIL, "数据错误，处理人业务日志信息为空！");
        }
        String procInstId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
        if (null == procVariables) {
            procVariables = new HashMap<>();
        }
        if (StringUtils.isNotEmpty(result)) {
            procVariables.put("result", result);
        } else {
            result = "提交";// 默认状态提交，不保存到流程变量中，记入业务处理日志状态中
        }
        Task processingtask = getByTaskQuery(taskId);
        String title = (String) msgVariables.get(ConstantUtil.FLOWABLE_MSG_TITLE);
        String content = (String) msgVariables.get(ConstantUtil.FLOWABLE_MSG_CONTENT);
        String businessType = ConstantConversionUtil.flowBusinessModuleCodes.get(key);
        if (null != processingtask) {
            if(assigneeId == null || !processingtask.getAssignee().equals(assigneeId.toString())) {
                throw new ValidatorException(CodeUtil.FAIL, "提交失败，您并不是该业务处理人！");
            }
            FlowActivityDefinition flowActDef = flowActDefService
                    .getByProcActKey(processingtask.getProcessDefinitionId(), processingtask.getTaskDefinitionKey());
            if (StringUtils.isNotEmpty(log.getTaskDefKey())) {
                log.setStatus(result);
                log.setEndTime(new Date());
                Float overdue = null;
                if (flowActDef.getWorkingDay()) {
                    overdue = FlowableUtil.getBusinessDeadlineByWorkingDay(log.getGmtCreate(),
                            flowActDef.getTimeLimit(), flowActDef.getWorkingDay());
                } else {
                    overdue = FlowableUtil.getBusinessOverdueByNatureDay(log.getGmtCreate(), flowActDef.getTimeLimit());
                }
                if (null != formBusinessId) {
                    log.setFormBusinessId(formBusinessId);
                }
                if (null != overdue && overdue < 0) {// 只展示逾期，故直接转换为正数
                    log.setOverdueDays(Math.abs(overdue));
                    log.setWorkingDay(flowActDef.getWorkingDay());
                }
                log.setEndTime(new Date());
                // 完成当前任务
                taskService.complete(taskId, procVariables);
                // 更新业务处理日志
                log.setUserModified("超级管理员");
                processingLogService.update(log);
                // 删除对应的可分配任务
                @SuppressWarnings("unchecked")
                List<Long> knowerList = (List<Long>) msgVariables
                        .get(processingtask.getTaskDefinitionKey() + ConstantUtil.KNOWERLIST);
                // 不可链接跳转处理信息，若knowerList为null或空，表示无知晓者
                if (null != knowerList && knowerList.size() > 0 && StringUtils.isNotEmpty(content)) {
                    if (processingtask.getTaskDefinitionKey().equals(ConstantUtil.REVIEW_MEETING_REVIEWPREPARE)) {// 特殊消息处理
                        sysMsgService.sendFlowMsgImmediately(title,
                                (String) msgVariables.get(processingtask.getTaskDefinitionKey()), knowerList,
                                entity.getId(), businessType, false, null);
                    } else {
                        sysMsgService.sendFlowMsgImmediately(title,
                                content.replace("inOut", "流出").replace("formBusiness", processingtask.getName())
                                        + ConstantUtil.FLOWABLE_MSG_KNOWER,
                                knowerList, entity.getId(), businessType, false, null);
                    }
                }
            }
        }
        // 判断是否结束，更新业务数据状态
        ProcessInstance procInst = runtimeService.createProcessInstanceQuery().processInstanceId(procInstId)
                .singleResult();
        boolean endFlag = false;
        boolean errorEndFlag = false;
        // 1.当前节点为最后一个节点，故办理完任务后，流程实例结束
        if (null == procInst || StringUtils.isEmpty(procInst.getId())) {
            endFlag = true;
            return true;
        } else {
            List<Task> pendingTasks = taskService.createTaskQuery().processInstanceId(procInst.getId()).list();
            if (null != pendingTasks && pendingTasks.size() > 0) {
                for (Task task : pendingTasks) {
                    // 流程业务待处理任务日志集合，注：一定要在循环内，同时过滤正在新增过的日志
                    List<String> pendingTaskIds = processingLogService.findPendingTaskByBusiness(entity.getId(), key);
                    // a.过滤掉已存在的并列或会签任务节点的日志信息
                    if (null != pendingTaskIds && pendingTaskIds.size() > 0 && pendingTaskIds.contains(task.getId())) {
                        continue;
                    }
                    // 任务办理人
                    // b.添加业务处理日志
                    BusinessProcessingLog processingLog = new BusinessProcessingLog();
                    processingLog.setBusnessKey(entity.getId());
                    processingLog.setBusinessType(key);
                    processingLog.setHistoricTaskId(task.getId());
                    if(assigneeId != null){
                        User assignee = new User();
                        assignee.setId(assigneeId);
                        processingLog.setAssignee(assignee);
                    }else {
                        User assignee = userService.get(Long.parseLong(task.getAssignee()));
                        if (task.getAssignee() != null) {
                            processingLog.setAssignee(assignee);
                        }
                    }
                    processingLog.setAssigneeType(ConstantConversionUtil.PROCESS_TASK);
                    processingLog.setTaskDefKey(task.getTaskDefinitionKey());
                    processingLog.setTaskName(task.getName());
                    processingLog.setStartTime(task.getCreateTime());
                    processingLogService.add(processingLog);
                    if(assigneeId == null){
                        User assignee = userService.get(Long.parseLong(task.getAssignee()));
                        if (assignee != null && assignee.getId() != null) {
                            // d.发送系统待办消息：执行者消息可链接跳转处理信息，知晓者不可以。
                            sysMsgService.sendFlowMsgImmediately(title,
                                    content.replace("inOut", "进入").replace("formBusiness", task.getName())
                                            + ConstantUtil.FLOWABLE_MSG_ASSIGNEE,
                                    Arrays.asList(assignee.getId()), entity.getId(), businessType, true, task.getId());
                        }
                    }
                }
                return true;
            } else {
                // 2.若当前节点不是最后一个节点，但办理条件，并不流转到下一个节点，这时候需要主动结束流程实例
                runtimeService.deleteProcessInstance(procInstId, result);
                errorEndFlag = true;
            }
        }
        // 空结束或终止（否决）结束事件
        // 异常结束事件
        if (errorEndFlag) {
            /**
             *
             */
        }
        return false;
    }

    @Override
    public Boolean completeMyTask(String taskId, Project entity, Map<String, Object> procVariables, String result,
                                  Long formBusinessId, Map<String, Object> msgVariables, String key, List<Long> receiverUserIds) {
        if (StringUtils.isEmpty(taskId)) {
            throw new ValidatorException(CodeUtil.FAIL, "任务ID为空");
        }
        if (entity == null || entity.getId() == null) {
            throw new ValidatorException(CodeUtil.FAIL, "流程业务ID为空");
        }
        if (formBusinessId == null) {
            throw new ValidatorException(CodeUtil.FAIL, "流程表单业务ID为空");
        }

        // 查看处理人最新的日志
        BusinessProcessingLog log = processingLogService.getLatestByTask(entity.getId(),
                key, taskId, ConstantConversionUtil.PROCESS_TASK);
        if (log == null) {
            throw new ValidatorException(CodeUtil.FAIL, "数据错误，处理人业务日志信息为空！");
        }
        String procInstId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
        if (null == procVariables) {
            procVariables = new HashMap<>();
        }
        if (StringUtils.isNotEmpty(result)) {
            procVariables.put("result", result);
        } else {
            result = "提交";// 默认状态提交，不保存到流程变量中，记入业务处理日志状态中
        }
        Task processingtask = getByTaskQuery(taskId);
        String title = (String) msgVariables.get(ConstantUtil.FLOWABLE_MSG_TITLE);
        String content = (String) msgVariables.get(ConstantUtil.FLOWABLE_MSG_CONTENT);
        String businessType = ConstantConversionUtil.flowBusinessModuleCodes.get(key);
        if (null != processingtask) {
            if (!processingtask.getAssignee().equals(ThreadLocalUtil.getUserId().toString())) {
                throw new ValidatorException(CodeUtil.FAIL, "提交失败，您并不是该业务处理人！");
            }
            FlowActivityDefinition flowActDef = flowActDefService
                    .getByProcActKey(processingtask.getProcessDefinitionId(), processingtask.getTaskDefinitionKey());
            if (StringUtils.isNotEmpty(log.getTaskDefKey())) {
                log.setStatus(result);
                log.setEndTime(new Date());
                Float overdue = null;
                if (flowActDef.getWorkingDay()) {
                    overdue = FlowableUtil.getBusinessDeadlineByWorkingDay(log.getGmtCreate(),
                            flowActDef.getTimeLimit(), flowActDef.getWorkingDay());
                } else {
                    overdue = FlowableUtil.getBusinessOverdueByNatureDay(log.getGmtCreate(), flowActDef.getTimeLimit());
                }
                if (null != formBusinessId) {
                    log.setFormBusinessId(formBusinessId);
                }
                if (null != overdue && overdue < 0) {// 只展示逾期，故直接转换为正数
                    log.setOverdueDays(Math.abs(overdue));
                    log.setWorkingDay(flowActDef.getWorkingDay());
                }
                log.setEndTime(new Date());
                // 完成当前任务
                taskService.complete(taskId, procVariables);
                // 更新业务处理日志
                processingLogService.update(log);
                // 删除对应的可分配任务
                @SuppressWarnings("unchecked")
                List<Long> knowerList = (List<Long>) msgVariables
                        .get(processingtask.getTaskDefinitionKey() + ConstantUtil.KNOWERLIST);
                // 不可链接跳转处理信息，若knowerList为null或空，表示无知晓者
                if (null != knowerList && knowerList.size() > 0 && StringUtils.isNotEmpty(content)) {
                    if (processingtask.getTaskDefinitionKey().equals(ConstantUtil.REVIEW_MEETING_REVIEWPREPARE)) {// 特殊消息处理
                        sysMsgService.sendFlowMsgImmediately(title,
                                (String) msgVariables.get(processingtask.getTaskDefinitionKey()), knowerList,
                                entity.getId(), businessType, false, null);
                    } else {
                        sysMsgService.sendFlowMsgImmediately(title,
                                content.replace("inOut", "流出").replace("formBusiness", processingtask.getName())
                                        + ConstantUtil.FLOWABLE_MSG_KNOWER,
                                knowerList, entity.getId(), businessType, false, null);
                    }
                }
            }
        }
        // 判断是否结束，更新业务数据状态
        ProcessInstance procInst = runtimeService.createProcessInstanceQuery().processInstanceId(procInstId)
                .singleResult();
        boolean endFlag = false;
        boolean errorEndFlag = false;
        // 1.当前节点为最后一个节点，故办理完任务后，流程实例结束
        if (null == procInst || StringUtils.isEmpty(procInst.getId())) {
            endFlag = true;
            return true;
        } else {
            List<Task> pendingTasks = taskService.createTaskQuery().processInstanceId(procInst.getId()).list();
            if (null != pendingTasks && pendingTasks.size() > 0) {
                for (Task task : pendingTasks) {
                    // 流程业务待处理任务日志集合，注：一定要在循环内，同时过滤正在新增过的日志
                    List<String> pendingTaskIds = processingLogService.findPendingTaskByBusiness(entity.getId(), key);
                    // a.过滤掉已存在的并列或会签任务节点的日志信息
                    if (null != pendingTaskIds && pendingTaskIds.size() > 0 && pendingTaskIds.contains(task.getId())) {
                        continue;
                    }
                    // 任务办理人
                    // b.添加业务处理日志
                    BusinessProcessingLog processingLog = new BusinessProcessingLog();
                    processingLog.setBusnessKey(entity.getId());
                    processingLog.setBusinessType(key);
                    processingLog.setHistoricTaskId(task.getId());
                    if (task.getAssignee() != null) {
                        User assignee = userService.get(Long.parseLong(task.getAssignee()));
                        processingLog.setAssignee(assignee);
                    }
                    processingLog.setAssigneeType(ConstantConversionUtil.PROCESS_TASK);
                    processingLog.setTaskDefKey(task.getTaskDefinitionKey());
                    processingLog.setTaskName(task.getName());
                    processingLog.setStartTime(task.getCreateTime());
                    processingLogService.add(processingLog);
                    // d.发送系统待办消息：执行者消息可链接跳转处理信息，知晓者不可以。
                    if (receiverUserIds != null && receiverUserIds.size() > 0) {
                        sysMsgService.sendFlowMsgImmediately(title,
                                content.replace("inOut", "进入").replace("formBusiness", task.getName())
                                        + ConstantUtil.FLOWABLE_MSG_ASSIGNEE,
                                receiverUserIds, entity.getId(), businessType, true, task.getId());
                    } else {
                        sysMsgService.sendFlowMsgImmediately(title,
                                content.replace("inOut", "进入").replace("formBusiness", task.getName())
                                        + ConstantUtil.FLOWABLE_MSG_ASSIGNEE,
                                Arrays.asList(userService.get(Long.parseLong(task.getAssignee())).getId()), entity.getId(), businessType, true, task.getId());
                    }
                }
                return true;
            } else {
                // 2.若当前节点不是最后一个节点，但办理条件，并不流转到下一个节点，这时候需要主动结束流程实例
                runtimeService.deleteProcessInstance(procInstId, result);
                errorEndFlag = true;
            }
        }
        // 空结束或终止（否决）结束事件
        // 异常结束事件
        if (errorEndFlag) {
            /**
             *
             */
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void claimTask(String taskId, Long userId, String roleName) {
        List<Long> userIds = userService.findUserIdByRole(roleName);
        if (userIds != null && userIds.size() > 0) {
            if (userIds.contains(userId)) {
                Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
                if (task.getAssignee() == null && task.getClaimTime() == null) {
                    taskService.claim(taskId, ThreadLocalUtil.getUserId().toString());
                    BusinessProcessingLog processingLog = processingLogService.findByHistoricTaskId(taskId);
                    if (processingLog != null) {
                        processingLog.setAssignee(userService.get(userId));
                        processingLogService.updateAssigneeId(processingLog);
                    }
                }
            } else {
                throw new BusinessException(CodeUtil.FAIL, "当前用户没有办理该任务权限!");
            }
        }else {
            throw new BusinessException(CodeUtil.FAIL,roleName + "角色下没有用户！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void claimTask(String taskId, Long userId, List<String> roleNames) {
        List<Long> userIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(roleNames)) {
            roleNames.stream().forEach(n -> {
                        List<Long> ids = userService.findUserIdByRole(n);
                        if (CollectionUtil.isNotEmpty(ids)) {
                            userIds.addAll(ids);
                        }
                    }
            );
        }
        if (userIds != null && userIds.size() > 0) {
            if (userIds.contains(userId)) {
                Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
                if (task.getAssignee() == null && task.getClaimTime() == null) {
                    taskService.claim(taskId, ThreadLocalUtil.getUserId().toString());
                    BusinessProcessingLog processingLog = processingLogService.findByHistoricTaskId(taskId);
                    if (processingLog != null) {
                        processingLog.setAssignee(userService.get(userId));
                        processingLogService.updateAssigneeId(processingLog);
                    }
                }
            } else {
                throw new BusinessException(CodeUtil.FAIL, "当前用户没有办理该任务权限!");
            }
        }
    }

    @Override
    public Boolean existTask(String historicTaskId) {
        Integer num = flowActivityDefinitionMapper.existTask(historicTaskId);
        if(num > 0 ){
            return true;
        }
        return false;
    }

    @Override
    public List<Task> findMyPendingList(String sourceBusinessId, String procDefinitionKey) {
        if (StringUtils.isEmpty(sourceBusinessId) || StringUtils.isEmpty(procDefinitionKey)) {
            throw new ValidatorException(CodeUtil.FAIL, "默认条件不能为空！");
        }
        return taskService.createTaskQuery().taskAssignee(ThreadLocalUtil.getUserId().toString())
                .processDefinitionKey(procDefinitionKey).processInstanceBusinessKey(sourceBusinessId).list();
    }
}
