/**
 * Copyright &copy; 2021-2026 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
 */
package com.jeeplus.flowable.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jeeplus.centerservice.service.ccpm.flow.FlowRequest;
import com.jeeplus.common.utils.Collections3;
import com.jeeplus.extension.domain.NodeSetting;
import com.jeeplus.extension.service.NodeSettingService;
import com.jeeplus.flowable.model.ActRuTaskInfo;
import com.jeeplus.flowable.model.Flow;
import com.jeeplus.flowable.model.TaskComment;
import com.jeeplus.flowable.service.FlowTaskService;
import com.jeeplus.centerservice.utils.ConvertServiceUtil;
import com.jeeplus.centerservice.utils.RestTemplateService;
import com.jeeplus.flowable.vo.HisTaskVo;
import com.jeeplus.flowable.vo.ProcessVo;
import com.jeeplus.mail.domain.Mail;
import com.jeeplus.mail.domain.MailBox;
import com.jeeplus.mail.domain.MailCompose;
import com.jeeplus.mail.service.MailBoxService;
import com.jeeplus.mail.service.MailComposeService;
import com.jeeplus.mail.service.MailService;
import com.jeeplus.sys.constant.CommonConstants;
import com.jeeplus.sys.service.dto.UserDTO;
import com.jeeplus.sys.utils.Global;
import com.jeeplus.sys.utils.UserUtils;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
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.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

/**
 * 流程个人任务相关Controller
 *
 * @author jeeplus
 * @version 2021-09-03
 */
@RestController
@RequestMapping("/flowable/task")
public class FlowableTaskController {

    @Autowired
    private FlowTaskService flowTaskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RuntimeService runtimeService;


    @Autowired
    private TaskService taskService;

    @Autowired
    private NodeSettingService nodeSettingService;

    @Autowired
    private MailComposeService mailComposeService;

    @Autowired
    private MailBoxService mailBoxService;

    @Autowired
    private MailService mailService;

    @Resource
    private RestTemplateService restTemplateService;

    @Resource
    private FlowRequest flowRequest;


    @GetMapping("todo")
    public ResponseEntity todoListData(Page <ProcessVo> page, Flow flow) throws Exception {
        //获取当前登陆人的信息
        UserDTO currentUserDTO = UserUtils.getCurrentUserDTO();
        //判定如果当前登陆人是否可以查看其他服务的待办信息
        if("1".equals(currentUserDTO.getOtherServiceFlag())){
            // 中台数据查询
            List<Map<String, Object>> cpa = queryTodoListCenter(flow, "cpa", Global.getConfig("INQUIRE_STATUS"));
            if (cpa.size() > 0) {
                List<ProcessVo> list = JSON.parseArray(JSON.toJSONString(cpa), ProcessVo.class);
                List<ProcessVo> processVos = ConvertServiceUtil.convertProcessVoList(list);
                // 将整合后的结果排序后分页
                Page sortAndPaging = ConvertServiceUtil.getSortAndPaging(page, processVos);
                return ResponseEntity.ok (sortAndPaging);
            } else {
                // 如果中台没有返回任何数据，就去查询本系统分页待办数据
                Page <ProcessVo> pageList = flowTaskService.todoList(page, flow, UserUtils.getCurrentUserDTO ().getId ());
                return ResponseEntity.ok (pageList);
            }
        }else{
            // 查询本系统分页待办数据
            Page <ProcessVo> pageList = flowTaskService.todoList(page, flow, UserUtils.getCurrentUserDTO ().getId ());
            return ResponseEntity.ok (pageList);
        }
    }

    /**
     * 查询待办信息后分发给所属系统
     * @param flow
     * @param belongProject 所属系统
     * @param inquireStatus 各服务引用状态 =》 （若包含，则进行获取该服务的流程信息）
     * @return
     * @throws Exception
     */
    @GetMapping("queryTodoListCenter")
    public List<Map<String,Object>> queryTodoListCenter(Flow flow,String belongProject,String inquireStatus) throws Exception {
        List<Map<String, Object>> result = new ArrayList<>();
        List<ProcessVo> processVoList = new ArrayList<>();
        // 任务数量（线程池的线程数量、计数器的值）
        int taskVolume = 2;
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(taskVolume);
        // 创建单次计数器（事实上就是创建多个锁，每次.countDown()会释放一把锁，使用.await()就是等待全部锁被释放，所以这个计数器是线程安全的）
        CountDownLatch countDownLatch = new CountDownLatch(taskVolume);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String currentUserId = UserUtils.getCurrentUserDTO ().getId ();
        // cpa线程任务
        Future<?> cpa = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("查询cpa待办开始"+sdf.format(new Date()));
                try {
                    // cpa系统待办数据查询
                    if (inquireStatus.contains("cpa") || ("cpa").equals(belongProject)) {
                        Page<ProcessVo> pageList = flowTaskService.todoList(new Page<>(1, -1), flow, currentUserId);
                        pageList.getRecords().stream().forEach(item -> {
                            item.setBelongProject("cpa");
                            // 查询审核人
                            if (Objects.nonNull(item.getTask()) && StringUtils.isNotBlank(item.getTask().getAssignee())) {
                                UserDTO userDTO = UserUtils.get(item.getTask().getAssignee());
                                if (Objects.nonNull(userDTO) && StringUtils.isNotBlank(userDTO.getName())) {
                                    item.getTask().setAssignee(userDTO.getName());
                                }
                            }
                        });
                        List<ProcessVo> processVos = pageList.getRecords();
                        processVoList.addAll(processVos);
                    }
                } catch (Exception e) {
                    System.out.println("cpa系统待办查询失败");
                    e.printStackTrace();
                }
                // 当前线程执行完毕，计数器 -1
                countDownLatch.countDown();
                System.out.println("查询cpa待办结束"+sdf.format(new Date()));
            }
        });
        // ccpm线程任务
        Future<?> ccpm = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("查询ccpm待办开始"+sdf.format(new Date()));
                try{
                    // ccpm系统待办数据查询
                    if (inquireStatus.contains("ccpm") || ("ccpm").equals(belongProject)) {
                        // 访问ccpm
                        Object response = flowRequest.getNotifyList(flow, belongProject);
                        if (Objects.nonNull(response)) {
                            List<Map<String, Object>> res = JSONObject.parseArray(JSON.toJSONString(response));
                            if (("ccpm").equals(belongProject)) { // 如果是ccpm系统查询，则直接返回
                                result.addAll(res);
                            } else { // 如果是其他系统查询，则将结果格式化后返回
                                if (CollectionUtil.isNotEmpty(res)) {
                                    List<ProcessVo> processVos = JSON.parseArray(JSON.toJSONString(res), ProcessVo.class);
                                    processVoList.addAll(processVos);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    System.out.println("ccpm系统待办查询失败");
                    e.printStackTrace();
                }
                // 当前线程执行完毕，计数器 -1
                countDownLatch.countDown();
                System.out.println("查询ccpm待办结束"+sdf.format(new Date()));
            }
        });
        // 阻塞 等待线程池任务执行完后再执行后面代码
        // 设置最大等待时间 5秒
        countDownLatch.await(5,TimeUnit.SECONDS);
        // 关闭线程池
        executorService.shutdown();
        // 根据不同系统返回不同字段值
        if ("cpa".equals(belongProject)) {
            result.addAll(JSON.parseArray(JSON.toJSONString(processVoList)));
        } else if ("ccpm".equals(belongProject)) {
            result.addAll(ConvertServiceUtil.copyNotifyListToCcpm(processVoList));
        }
        return result;
    }

    @GetMapping("allTodo")
    public ResponseEntity allTodo(Flow flow) {
        String currentUserId = UserUtils.getCurrentUserDTO ().getId ();
        Page <ProcessVo> pageList = flowTaskService.todoList(new Page<>(1, -1), flow, currentUserId);
        pageList.getRecords().stream().forEach(item->{
            // 查询审核人
            if (Objects.nonNull(item.getTask()) && StringUtils.isNotBlank(item.getTask().getAssignee())) {
                UserDTO userDTO = UserUtils.get(item.getTask().getAssignee());
                if (Objects.nonNull(userDTO) && StringUtils.isNotBlank(userDTO.getName())) {
                    item.getTask().setAssignee(userDTO.getName());
                }
            }
        });
        return ResponseEntity.ok (pageList.getRecords());
    }

    /**
     * 获取已办任务
     *
     * @return
     */
    @GetMapping("historic")
    public ResponseEntity historicListData(Page<HisTaskVo> page, Flow flow) throws Exception {
        //获取当前登陆人的信息
        UserDTO currentUserDTO = UserUtils.getCurrentUserDTO();
        //判定如果当前登陆人是否可以查看其他服务的已办信息
        if("1".equals(currentUserDTO.getOtherServiceFlag())){
            // 中台数据查询
            List<Map<String, Object>> cpa = queryHistoricListCenter(flow, "cpa", Global.getConfig("INQUIRE_STATUS"));
            if (cpa.size() > 0) {
                List<HisTaskVo> list = JSON.parseArray(JSON.toJSONString(cpa), HisTaskVo.class);
                List<HisTaskVo> hisTaskVos = ConvertServiceUtil.convertHisTaskVoList(list);
                // 将整合后的结果排序后分页
                Page sortAndPaging = ConvertServiceUtil.getSortAndPagingHisTask(page, hisTaskVos);
                return ResponseEntity.ok (sortAndPaging);
            } else {
                // 如果中台没有返回任何数据，就去查询本系统分页已办数据
                Page <HisTaskVo> pageList = flowTaskService.historicList(page, flow, currentUserDTO);
                return ResponseEntity.ok (pageList);
            }
        }else{
            // 查询本系统分页已办数据
            Page <HisTaskVo> pageList = flowTaskService.historicList(page, flow, currentUserDTO);
            return ResponseEntity.ok (pageList);
        }
    }

    @GetMapping("queryHistoricListCenter")
    public List<Map<String,Object>> queryHistoricListCenter(Flow flow,String belongProject,String inquireStatus) throws Exception {
        List<Map<String, Object>> result = new ArrayList<>();
        List<HisTaskVo> hisTaskVoList = new ArrayList<>();
        // 任务数量（线程池的线程数量、计数器的值）
        int taskVolume = 2;
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(taskVolume);
        // 创建单次计数器（事实上就是创建多个锁，每次.countDown()会释放一把锁，使用.await()就是等待全部锁被释放，所以这个计数器是线程安全的）
        CountDownLatch countDownLatch = new CountDownLatch(taskVolume);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 获取当前登录人信息
        UserDTO currentUserDTO = UserUtils.getCurrentUserDTO();
        // cpa线程任务
        Future<?> cpa = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("查询cpa已办开始"+sdf.format(new Date()));
                try {
                    // cpa系统已办数据查询
                    if (inquireStatus.contains("cpa") || ("cpa").equals(belongProject)) {
                        Page<HisTaskVo> pageList = flowTaskService.historicList(new Page<>(1, -1), flow, currentUserDTO);
                        pageList.getRecords().stream().forEach(item -> {
                            item.setBelongProject("cpa");
                            // 设置 processDefKey
                            if (StringUtils.isNotBlank(item.getProcessDefinitionId())) {
                                String[] split = item.getProcessDefinitionId().split(":");
                                if(split.length>0) {
                                    item.setProcessDefKey(split[0]);
                                }
                            }
                            // 设置 businessId
                            HistoricProcessInstance finishedProcIns = flowTaskService.getFinishedProcIns(item.getProcessInstanceId());
                            if (finishedProcIns != null && finishedProcIns.getBusinessKey() != null && finishedProcIns.getBusinessKey().contains(":")) {
                                String[] ss = finishedProcIns.getBusinessKey().split(":");
                                item.setBusinessId(ss[1]);
                            } else if (finishedProcIns != null && finishedProcIns.getBusinessKey() != null) {
                                item.setBusinessId(finishedProcIns.getBusinessKey());
                            }
                        });
                        hisTaskVoList.addAll(pageList.getRecords());
                    }
                } catch (Exception e) {
                    System.out.println("cpa系统已办查询失败");
                    e.printStackTrace();
                }
                // 当前线程执行完毕，计数器 -1
                countDownLatch.countDown();
                System.out.println("查询cpa已办结束"+sdf.format(new Date()));
            }
        });
        // ccpm线程任务
        Future<?> ccpm = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("查询ccpm已办开始"+sdf.format(new Date()));
                try{
                    // ccpm系统待办数据查询
                    if (inquireStatus.contains("ccpm") || ("ccpm").equals(belongProject)) {
                        // 访问ccpm
                        Object response = flowRequest.getHisTaskList(flow, belongProject);
                        if (Objects.nonNull(response)) {
                            List<Map<String, Object>> res = JSONObject.parseArray(JSON.toJSONString(response));
                            if (("ccpm").equals(belongProject)) { // 如果是ccpm系统查询，则直接返回
                                result.addAll(res);
                            } else { // 如果是其他系统查询，则将结果格式化后返回
                                if (CollectionUtil.isNotEmpty(res)) {
                                    List<HisTaskVo> hisTaskVos = JSON.parseArray(JSON.toJSONString(res), HisTaskVo.class);
                                    hisTaskVoList.addAll(hisTaskVos);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    System.out.println("ccpm系统已办查询失败");
                    e.printStackTrace();
                }
                // 当前线程执行完毕，计数器 -1
                countDownLatch.countDown();
                System.out.println("查询ccpm已办结束"+sdf.format(new Date()));
            }
        });
        // 阻塞 等待线程池任务执行完后再执行后面代码
        // 设置最大等待时间 5秒
        countDownLatch.await(5,TimeUnit.SECONDS);
        // 关闭线程池
        executorService.shutdown();
        // 根据不同系统返回不同字段值
        if ("cpa".equals(belongProject)) {
            result.addAll(JSON.parseArray(JSON.toJSONString(hisTaskVoList)));
        } else if ("ccpm".equals(belongProject)) {
            result.addAll(ConvertServiceUtil.copyHisTaskListToCcpm(hisTaskVoList));
        }
        return result;
    }

    /**
     * 获取我的申请列表
     *
     * @return
     */
    @GetMapping("myApplyed")
    public ResponseEntity myApplyedListData( Page<ProcessVo> page, Flow flow) throws Exception {
        page = flowTaskService.getMyStartedProcIns( UserUtils.getCurrentUserDTO (), page, flow);
        return ResponseEntity.ok ( page );
    }


    /**
     * 获取任务流转历史列表
     *
     */
    @GetMapping("historicTaskList")
    public ResponseEntity historicTaskList(Flow flow) throws Exception {
        List<Flow> historicTaskList = flowTaskService.historicTaskList (flow.getProcInsId());
        return ResponseEntity.ok ( historicTaskList );
    }


    /**
     * 获取流程表单
     */
    @GetMapping("getTaskDef")
    public ResponseEntity getTaskDef(Flow flow) {
        /*if(StringUtils.isNotBlank(flow.getTaskId()) && StringUtils.isBlank(flow.getTaskName()) && StringUtils.isBlank(flow.getTaskDefKey())){
            ActRuTaskInfo taskInfoByTaskId = flowTaskService.getTaskInfoByTaskId(flow.getTaskId());
            if(null != taskInfoByTaskId){
                flow.setTaskId(taskInfoByTaskId.getId());
                flow.setProcInsId(taskInfoByTaskId.getProcInstId());
                flow.setTaskName(taskInfoByTaskId.getName());
                flow.setTaskDefKey(taskInfoByTaskId.getTaskDefKey());
            }
        }*/
        // 获取流程XML上的表单KEY
        String formKey = flowTaskService.getFormKey(flow.getProcDefId(), flow.getTaskDefKey());

        NodeSetting typeNode = nodeSettingService.queryByKey (flow.getProcDefKey(), flow.getTaskDefKey(), "formType");
        NodeSetting ReadOnlyNode = nodeSettingService.queryByKey (flow.getProcDefKey(), flow.getTaskDefKey(), "formReadOnly");
        String formType = "1";
        boolean formReadOnly = false;
        if(typeNode != null){
           formType = typeNode.getValue ();
           formReadOnly = "true".equals(ReadOnlyNode.getValue ());
        }else{
           if(StringUtils.isBlank(formKey)){
               formType = "1";
           }else if(formKey.indexOf("/")>=0){
               formType = "2";
           }
        }

        // 获取流程实例对象
        if (flow.getProcInsId() != null) {
            if (flowTaskService.getProcIns(flow.getProcInsId()) != null) {
                flow.setProcIns(flowTaskService.getProcIns(flow.getProcInsId()));
            } else {
                flow.setFinishedProcIns(flowTaskService.getFinishedProcIns(flow.getProcInsId()));
            }
        }

        flow.setFormUrl(formKey);
        flow.setFormReadOnly(formReadOnly);
        flow.setFormType(formType);
        return ResponseEntity.ok (flow);
    }




    /**
     * 获取流程表单
     */
    @GetMapping("getTaskDefInfo")
    public ResponseEntity getTaskDefInfo(Flow flow) {
        if(StringUtils.isNotBlank(flow.getTaskId()) && StringUtils.isBlank(flow.getTaskName()) && StringUtils.isBlank(flow.getTaskDefKey())){
            ActRuTaskInfo taskInfoByTaskId = flowTaskService.getTaskInfoByTaskId(flow.getTaskId());
            if(null != taskInfoByTaskId){
                flow.setTaskId(taskInfoByTaskId.getId());
                flow.setProcInsId(taskInfoByTaskId.getProcInstId());
                flow.setTaskName(taskInfoByTaskId.getName());
                flow.setTaskDefKey(taskInfoByTaskId.getTaskDefKey());
            }
            //当前任务信息
            Task task =taskService.createTaskQuery().processInstanceId(flow.getProcInsId()).active().singleResult();
            if(null != task){
                if(StringUtils.isNotBlank(task.getProcessDefinitionId())){
                    flow.setProcDefId(task.getProcessDefinitionId());
                }
                if(null != task.getProcessVariables ()){
                    String title = (String) task.getProcessVariables().get("title");
                    if(StringUtils.isNotBlank(title)){
                        flow.setTitle(title);
                    }else{
                        flow.setTitle("");
                    }
                }
            }

            Process process = SpringUtil.getBean (RepositoryService.class).getBpmnModel (taskInfoByTaskId.getProcDefId ()).getMainProcess ();
            if(null != process && StringUtils.isNotBlank(process.getId())){
                flow.setProcDefKey(process.getId());
            }
        }
        // 获取流程XML上的表单KEY
        String formKey = flowTaskService.getFormKey(flow.getProcDefId(), flow.getTaskDefKey());

        NodeSetting typeNode = nodeSettingService.queryByKey (flow.getProcDefKey(), flow.getTaskDefKey(), "formType");
        NodeSetting ReadOnlyNode = nodeSettingService.queryByKey (flow.getProcDefKey(), flow.getTaskDefKey(), "formReadOnly");
        String formType = "1";
        boolean formReadOnly = false;
        if(typeNode != null){
            formType = typeNode.getValue ();
            formReadOnly = "true".equals(ReadOnlyNode.getValue ());
        }else{
            if(StringUtils.isBlank(formKey)){
                formType = "1";
            }else if(formKey.indexOf("/")>=0){
                formType = "2";
            }
        }

        // 获取流程实例对象
        if (flow.getProcInsId() != null) {
            if (flowTaskService.getProcIns(flow.getProcInsId()) != null) {
                flow.setProcIns(flowTaskService.getProcIns(flow.getProcInsId()));
            } else {
                flow.setFinishedProcIns(flowTaskService.getFinishedProcIns(flow.getProcInsId()));
            }
        }

        flow.setFormUrl(formKey);
        flow.setFormReadOnly(formReadOnly);
        flow.setFormType(formType);
        return ResponseEntity.ok (flow);
    }



    /**
     * 启动流程
     */
    @PostMapping("start")
    public ResponseEntity start(@RequestBody  Flow flow)  {
        String procInsId = flowTaskService.startProcess(flow.getProcDefKey(), flow.getBusinessTable(), flow.getBusinessId(), flow.getTitle(), flow.getProcDefId());

        //指定下一步处理人
        if(StringUtils.isNotBlank(flow.getAssignee ())){
            Task task = taskService.createTaskQuery().processInstanceId(procInsId).active().singleResult();
            if(task != null){
                String[] split = flow.getAssignee().split(",");
                if (split.length == 1) {
                    taskService.setAssignee(task.getId(), flow.getAssignee ());
                } else {
                    for (String i : split) {
                        taskService.addCandidateUser(task.getId(),i);
                    }
                }


            }
        }
        return ResponseEntity.ok (procInsId);
    }

    /**
     * 签收任务
     */
    @PostMapping("claim")
    public ResponseEntity claim(@RequestBody Flow flow) {
        String userId = UserUtils.getCurrentUserDTO ().getId();//ObjectUtils.toString(UserUtils.getUser().getId());
        flowTaskService.claim(flow.getTaskId(), userId);
        return ResponseEntity.ok ("签收成功!");
    }

    /**
     * 完成任务
     */
    @PostMapping( value = "complete")
    public ResponseEntity complete(@RequestBody Flow flow) {
        flowTaskService.complete(flow, flow.getVars().getVariableMap());
        return ResponseEntity.ok ("完成任务!");
    }

    /**
     * 读取流程历史数据，用于渲染流程图
     */
    @GetMapping("getFlowChart")
    public Map getFlowChart(String processInstanceId) throws Exception {
        return flowTaskService.getDiagram(processInstanceId);
    }

    /**
     * 删除任务
     *
     * @param taskId 流程实例ID
     * @param reason 删除原因
     */
    @DeleteMapping("deleteTask")
    public ResponseEntity deleteTask(String taskId, String reason) {
        if (StringUtils.isBlank(reason)) {
            return ResponseEntity.badRequest ().body ("请填写删除原因");
        } else {
            flowTaskService.deleteTask(taskId, reason);
            return ResponseEntity.ok ("删除任务成功，任务ID=" + taskId);
        }
    }

    /**
     * 加签
     */
    @PostMapping("addSignTask")
    public ResponseEntity addSignTask(String taskId, String userIds, String comment, Boolean flag) throws Exception {
        flowTaskService.addSignTask (taskId, Arrays.asList (userIds.split (",")), comment, flag);
        return ResponseEntity.ok ("加签成功!");
    };


    /**
     * 审批
     *
     * @param flow
     */
    @PostMapping("audit")
    public ResponseEntity auditTask(HttpServletRequest request, Flow flow) {

        /*if(StringUtils.isNotBlank(flow.getTaskId()) && StringUtils.isBlank(flow.getTaskName()) && StringUtils.isBlank(flow.getTaskDefKey())){
            ActRuTaskInfo taskInfoByTaskId = flowTaskService.getTaskInfoByTaskId(flow.getTaskId());
            if(null != taskInfoByTaskId){
                flow.setTaskId(taskInfoByTaskId.getId());
                flow.setProcInsId(taskInfoByTaskId.getProcInstId());
                flow.setTaskName(taskInfoByTaskId.getName());
                flow.setTaskDefKey(taskInfoByTaskId.getTaskDefKey());
            }
        }*/
        Map<String, Object> vars = Maps.newHashMap();
        Map<String, String[]> map = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : map.entrySet()) {
            if(entry.getKey().startsWith("vars.")){
                String key = entry.getKey().substring(5);
                String value = entry.getValue()[0];
                if("true".equals(value) || "false".equals(value)){
                    vars.put(key, Boolean.valueOf(value).booleanValue());
                }else{
                    vars.put(key, value);
                }
            }
        }

        flowTaskService.auditSave(flow, vars);
        //指定下一步处理人
        if(StringUtils.isNotBlank(flow.getAssignee ())){
           Task task = taskService.createTaskQuery().processInstanceId(flow.getProcInsId()).active().singleResult();
           if(task != null){
               taskService.setAssignee(task.getId(), flow.getAssignee ());
           }
        }
        return ResponseEntity.ok (flow.getProcInsId ());
    }

    /**
     * 取回已经执行的任务，只有在下一任务节点未执行或者未签收时才能取回
     */
    @RequestMapping("callback")
    public ResponseEntity callback(@Param("preTaskId") String preTaskId,
                             @Param("currentTaskId") String currentTaskId,
                             @Param("processInstanceId") String processInstanceId,
                             @Param("preTaskDefKey") String preTaskDefKey,
                             @Param("currentTaskDefKey") String currentTaskDefKey) {
        try {
            // 取得流程实例
            ProcessInstance instance = runtimeService
                    .createProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .singleResult();
            if (instance == null) {
                return ResponseEntity.badRequest ().body ("流程已经结束");
            }

            //在已办任务列表中清除该任务信息
            historyService.deleteHistoricTaskInstance(preTaskId);

            List currTasks = Lists.newArrayList();
            currTasks.add(currentTaskDefKey);
            //回退到上一节点
            runtimeService.createChangeActivityStateBuilder()
                    .processInstanceId(instance.getId())
                    .moveActivityIdsToSingleActivityId(currTasks, preTaskDefKey).changeState();
            historyService.deleteHistoricTaskInstance(currentTaskId);
            return ResponseEntity.ok ("取回成功");
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.badRequest ().body ("流程取回失败，未知错误.");
        }
    }



    /**
     * 委托任务
     *
     * @param taskId 任务ID
     */
    @RequestMapping("delegate")
    public ResponseEntity delegate(String taskId, String userId) {
        if (StringUtils.isBlank(taskId) || StringUtils.isBlank(userId)) {
            return ResponseEntity.badRequest ().body ("参数异常");
        }
        taskService.setOwner (taskId, UserUtils.getCurrentUserDTO ().getId ());// 委托人为任务的拥有者
        taskService.delegateTask(taskId, userId);
        return ResponseEntity.ok ("委托成功");
    }

    /**
     * 取消签收任务
     *
     * @param taskId 任务ID
     */
    @RequestMapping("unclaim")
    public ResponseEntity unclaim(String taskId) {
        taskService.unclaim(taskId);
        return ResponseEntity.ok ("取消签收成功");
    }

    /**
     * 转派任务
     *
     * @param taskId   任务ID
     * @param userId 接收人
     */
    @PutMapping("transfer")
    public ResponseEntity transferTask(String taskId, String userId) {
        if (StringUtils.isBlank(userId) || StringUtils.isBlank(taskId)) {
            return ResponseEntity.badRequest ().body ("转派失败, 参数异常");
        }
        // 设置当前流程任务办理人
        Authentication.setAuthenticatedUserId(UserUtils.getCurrentUserDTO ().getId());
        taskService.setAssignee(taskId, userId);
        return ResponseEntity.ok ("转派成功!");
    }

    /**
     * 获取可退回任务节点
     * @param taskId
     * @return
     */
    @RequestMapping(value = "/backNodes")
    public ResponseEntity backNodes(@RequestParam String taskId) {
        List<Flow> nodes = flowTaskService.getBackNodes(taskId);
        return ResponseEntity.ok (nodes);
    }

    /**
     * 驳回任务到指定节点
     */
    @RequestMapping(value = "/back")
    public ResponseEntity back(String backTaskDefKey, String taskId, TaskComment comment) {

        String procInsId = flowTaskService.backTask(backTaskDefKey, taskId, comment);
        Task task = taskService.createTaskQuery().processInstanceId(procInsId).active().singleResult();
        if (ObjectUtil.isNotEmpty(task)) {
            if (com.jeeplus.sys.utils.StringUtils.isNotBlank(task.getId())){
                if (ObjectUtil.isNotEmpty(comment)) {
                    if (com.jeeplus.sys.utils.StringUtils.isNotBlank(comment.getCandidateUserList())) {
                        String[] split = comment.getCandidateUserList().split(",");
                        if (split.length == 1) {
                            taskService.setAssignee(task.getId(),split[0]);
                        }else{
                            for (String i : split) {
                                taskService.addCandidateUser(task.getId(),i);
                            }
                        }
                    }
                }
            }
        }
        return ResponseEntity.ok (procInsId);
    }

    /**
     * 催办任务
     *
     * @param taskId 任务ID
     */
    @PostMapping("urge")
    public ResponseEntity<String> urge(String taskId, String content) {
        List<UserDTO> assignList = Lists.newArrayList ( );
        taskService.getIdentityLinksForTask ( taskId ).forEach ( identityLink -> {
            assignList.add ( UserUtils.get ( identityLink.getUserId ( ) ) );
        } );
        String assignIds = Collections3.extractToString ( assignList, "id", ",");
        //发送邮件
        Mail mail = new Mail();
        mail.setTitle ( "你收到一条流程催办任务!" );
        mail.setContent ( content + "<p><a href=\"/#/flowable/task/TodoList\" target=\"_blank\">点击处理</a><br></p>" );

        //保存邮件内容
        mailService.saveOrUpdate ( mail );
        MailCompose mailCompose = new MailCompose ();
        mailCompose.setMailId ( mail.getId () );
        Date date = new Date ( System.currentTimeMillis ( ) );
        mailCompose.setSendTime ( date );
        mailCompose.setStatus ( CommonConstants.YES );
        mailCompose.setReceiverIds ( assignIds );
        mailCompose.setSenderId ( UserUtils.getCurrentUserDTO ().getId () );
        mailComposeService.saveOrUpdate ( mailCompose );
        for (UserDTO receiver : assignList) {
                MailBox mailBox = new MailBox ( );
                mailBox.setReadStatus ( CommonConstants.NO);
                mailBox.setReceiverIds (assignIds );
                mailBox.setReceiverId ( receiver.getId ( ) );
                mailBox.setSenderId ( UserUtils.getCurrentUserDTO ( ).getId ( ) );
                mailBox.setMailId ( mail.getId () );
                mailBox.setSendTime ( date );
                mailBoxService.saveOrUpdate ( mailBox );
            //发送通知到客户端
        }

        return ResponseEntity.ok ("催办成功!");
    }


}
