/**
 * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
 */
package com.jeeplus.modules.flowable.web;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jeeplus.common.json.AjaxJson;
import com.jeeplus.common.utils.SpringContextHolder;
import com.jeeplus.core.persistence.Page;
import com.jeeplus.core.web.BaseController;
import com.jeeplus.modules.extension.entity.FormSetting;
import com.jeeplus.modules.extension.service.FormSettingService;
import com.jeeplus.modules.flowable.entity.Flow;
import com.jeeplus.modules.flowable.service.FlowTaskService;
import com.jeeplus.modules.sys.utils.UserUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.flowable.bpmn.model.ExtensionAttribute;
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.runtime.ProcessInstance;
import org.flowable.form.api.FormInfo;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

    @Autowired
    private FlowTaskService flowTaskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private FormSettingService formSettingService;


    @GetMapping("todo")
    public AjaxJson todoListData(Flow flow, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
        Page<HashMap<String, String>> page = flowTaskService.todoList(new Page<HashMap<String, String>>(request, response), flow);
        return AjaxJson.success().put("page", page);
    }

    /**
     * 获取已办任务
     *
     * @return
     */
    @GetMapping("historic")
    public AjaxJson historicListData(Flow flow, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
        Page<HashMap<String, String>> page = flowTaskService.historicList(new Page<HashMap<String, String>>(request, response), flow);
        return AjaxJson.success().put("page", page);
    }

    /**
     * 获取我的申请列表
     *
     * @return
     */
    @GetMapping("myApplyed")
    public AjaxJson myApplyedListData(Flow flow, HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
        Page<HashMap> page = flowTaskService.getMyStartedProcIns(UserUtils.getUser(), new Page<HashMap>(request, response), flow);
        return AjaxJson.success().put("page", page);
    }


    /**
     * 获取流转历史列表
     *
     * @param startFlow 开始活动节点名称
     * @param endFlow   结束活动节点名称
     */
    @GetMapping("histoicFlowList")
    public AjaxJson histoicFlowList(Flow flow, String startFlow, String endFlow, Model model) {
        List<Flow> histoicFlowList = flowTaskService.histoicFlowList(flow.getProcInsId(), "", "");
        return AjaxJson.success().put("histoicFlowList", histoicFlowList);
    }


    /**
     * 获取流程表单
     */
    @GetMapping("getTaskDef")
    public AjaxJson getTaskDef(Flow flow) {
        // 获取流程XML上的表单KEY
        String formKey = flowTaskService.getFormKey(flow.getProcDefId(), flow.getTaskDefKey());
        FormSetting formSetting = formSettingService.queryByDefIdAndTaskId(flow.getProcDefKey(), flow.getTaskDefKey());
        String formType = "1";
        boolean formReadOnly = false;
        if(formSetting != null){
            formType = formSetting.getFormType();
           formReadOnly = "true".equals(formSetting.getFormReadOnly());
        }else{
           if(StringUtils.isBlank(formKey)){
               formType = "1";
           }else if(formKey.indexOf("/")>=0 || formKey.length() != 32){
               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 AjaxJson.success().put("flow", flow);
    }



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

        //指定下一步处理人
        if(StringUtils.isNotBlank(assign)){
            Task task = taskService.createTaskQuery().processInstanceId(procInsId).active().singleResult();
            if(task != null){
                taskService.setAssignee(task.getId(), assign);
            }
        }
        return AjaxJson.success("启动成功!").put("procInsId", procInsId);
    }

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

    /**
     * 完成任务
     * vars.keys=flag,pass
     * vars.values=1,true
     * vars.types=S,B  @see com.jeeplus.jeeplus.modules.act.utils.PropertyType
     */
    @PostMapping( value = "complete")
    public AjaxJson complete(Flow flow) {
        flowTaskService.complete(flow.getTaskId(), flow.getProcInsId(), flow.getComment(), flow.getVars().getVariableMap());
        return AjaxJson.success("完成任务!");
    }

    /**
     * 读取带跟踪的图片
     */
    @GetMapping("getFlowChart")
    public Map getFlowChart(String processInstanceId, HttpServletResponse response) throws Exception {
        return flowTaskService.getDiagram(processInstanceId, response);
    }

    /**
     * 输出跟踪流程信息
     *
     * @return
     * @throws Exception
     */
    @GetMapping("trace/info/{proInsId}")
    public AjaxJson traceInfo(@PathVariable("proInsId") String proInsId) throws Exception {
        List<Map<String, Object>> activityInfos = flowTaskService.traceProcess(proInsId);
        return AjaxJson.success().put("activityInfos", activityInfos);
    }

    /**
     * 删除任务
     *
     * @param taskId 流程实例ID
     * @param reason 删除原因
     */
    @RequiresPermissions("act:process:edit")
    @DeleteMapping("deleteTask")
    public AjaxJson deleteTask(String taskId, String reason) {
        if (StringUtils.isBlank(reason)) {
            return AjaxJson.error("请填写删除原因");
        } else {
            flowTaskService.deleteTask(taskId, reason);
            return AjaxJson.success("删除任务成功，任务ID=" + taskId);
        }
    }

    /**
     * 审批
     *
     * @param flow
     */
    @PostMapping("audit")
    public AjaxJson auditTask(HttpServletRequest request, Flow flow, String assign) {
        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);
                }
            }
        }
        AjaxJson j = new AjaxJson();
        flowTaskService.auditSave(flow, vars);
        //指定下一步处理人
        if(StringUtils.isNotBlank(assign)){
           Task task = taskService.createTaskQuery().processInstanceId(flow.getProcInsId()).active().singleResult();
           if(task != null){
               taskService.setAssignee(task.getId(), assign);
           }
        }
        return AjaxJson.success("提交成功");
    }

    /**
     * 取回已经执行的任务，只有在下一任务节点未执行或者未签收时才能取回
     */
    @PostMapping("callback")
    public AjaxJson 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 AjaxJson.error("流程已经结束");
            }

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

            List currTasks = Lists.newArrayList();
            currTasks.add(currentTaskDefKey);
            //回退到上一节点
            runtimeService.createChangeActivityStateBuilder()
                    .processInstanceId(instance.getId())
                    .moveActivityIdsToSingleActivityId(currTasks, preTaskDefKey).changeState();
            historyService.deleteHistoricTaskInstance(currentTaskId);

            return AjaxJson.success("取回成功");
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxJson.error("流程取回失败，未知错误.");
        }
    }



    /**
     * 委托任务
     *
     * @param taskId 任务ID
     */
    @PostMapping("delegate")
    public AjaxJson delegate(String taskId, String userId) {
        if (StringUtils.isBlank(taskId) || StringUtils.isBlank(userId)) {
            return AjaxJson.error("参数异常");
        }
        taskService.delegateTask(taskId, userId);
        return AjaxJson.success("委托成功");
    }

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

    /**
     * 转派任务
     *
     * @param taskId   任务ID
     * @param userId 接收人
     * @param reason   原因
     */
    @PostMapping("transfer")
    public AjaxJson transferTask(String taskId, String userId, String reason) {
        if (StringUtils.isBlank(userId) || StringUtils.isBlank(taskId)) {
            return AjaxJson.error("转派失败, 参数异常");
        }
        // 设置当前流程任务办理人
        Authentication.setAuthenticatedUserId(UserUtils.getUser().getId());
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        taskService.addComment(taskId, task.getProcessInstanceId(), "[转派] " + reason);
        taskService.setAssignee(taskId, userId);
        return AjaxJson.success("转派成功!");
    }


}
