package com.sinosig.activiti.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.sinosig.activiti.service.IWFCoreService;
import com.sinosig.activiti.service.external.UniWFService;
import com.sinosig.activiti.util.SecurityUtil;
import com.sinosig.activiti.util.WFGoToUtil;
import com.sinosig.activiti.util.WFResultUtil;
import com.sinosig.activiti.util.domain.WFSTEPACTORDTO;
import org.activiti.api.process.model.ProcessInstance;
import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.model.Task;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class WFCoreService implements IWFCoreService {

    @Autowired
    ProcessRuntime  processRuntime;
    @Autowired
    TaskRuntime taskRuntime;
    @Autowired
    RepositoryService repositoryService;
    @Autowired
    HistoryService historyService;
    @Autowired
    SecurityUtil securityUtil;
    @Autowired
    WFGoToUtil wfGoToUtil;
    @Autowired
    TaskService taskService;
    @Autowired
    UniWFService uniWfService;
    @Autowired
    RuntimeService runtimeService;

    @Override
    public JSONObject wfStart(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs("system");

        //获取部署标识
        String deployId=et.getString("deployid");

        //统一流程实例
        JSONObject uniwfInstanceId=et.getJSONObject("wfinstance");

        //流程中状态值
        String uniwfWorkingState=et.getString("workingstate");

        //业务数据标识
        String uniwfBSData=et.getString("bsdata");

        if (StringUtils.isEmpty(deployId) ||  ObjectUtils.isEmpty(uniwfInstanceId) || StringUtils.isEmpty(uniwfWorkingState) )
            return WFResultUtil.error("参数输入错误，请求参数中需包含 [deployid] 、[wfInstance]、[workingState] ") ;

        //通过部署标识获取流程定义
        List <ProcessDefinition> processDef=repositoryService.createProcessDefinitionQuery().deploymentId(deployId).list();

        if(ObjectUtils.isEmpty(processDef) || processDef.size()==0)
            return WFResultUtil.error(String.format("未能查询到[%s]流程定义",deployId)) ;

        //获取流程定义标识
        String processDefId=processDef.get(0).getId();

        //准备流程参数
        Map<String, Object> variables = getVariables(et);

        //流程中状态值
        variables.put("workingState",uniwfWorkingState);

        //获取流程下一步审批人
        WFSTEPACTORDTO uniwfStepActor= uniWfService.calculatenextWFSTEPACTOR();

        //设置流程下一步审批人
        variables.put("nextperson",uniwfStepActor.getWFUSERId());

        //启动流程
        ProcessInstance instance=processRuntime.start(ProcessPayloadBuilder.start().withProcessDefinitionId(processDefId).withBusinessKey(uniwfBSData).withVariables(variables).build());

        if(ObjectUtils.isEmpty(instance))
            return WFResultUtil.error("启动流程失败") ;

        //更新统一的流程实例
        uniWfService.wfStartCallbackByInst(instance);

        //建立统一待办
        uniWfService.wfStartCallbackByTask(instance);

        JSONObject resultData=WFResultUtil.success("流程启动成功");
        resultData.put("curstep","");

        return  resultData ;

    }

    @Override
    public JSONObject wfSubmit(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs("system");

        //要提交的任务标识
        JSONObject uniwfWorkList=et.getJSONObject("wfworklist");

        if (ObjectUtils.isEmpty(uniwfWorkList))
            WFResultUtil.error("参数输入错误，请求参数中需包含 [wfworklist]") ;

        String uniwfWorklistId=uniwfWorkList.getString("wfworklistid");

        String taskId=uniwfWorkList.getString("wfengineworklistid");

        if(StringUtils.isEmpty(taskId) || StringUtils.isEmpty(uniwfWorklistId))
            WFResultUtil.error("参数输入错误，请求参数中需包含 [wfengineworklistid] 、[wfworklistid]  ") ;

        //准备流程参数
        Map<String, Object> variables=getVariables(et);

        Task cur_task =taskRuntime.task(taskId);

        //属于候选者的任务，则先接收任务，再完成任务
        if(StringUtils.isEmpty(cur_task.getAssignee())){
            taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(taskId).build());
        }

        //获取流程下一步审批人
        WFSTEPACTORDTO uniwfStepActor= uniWfService.calculatenextWFSTEPACTOR();

        //设置流程下一步审批人
        variables.put("nextperson",uniwfStepActor.getWFUSERId());

        //提交任务
        org.activiti.api.task.model.Task task=taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskId).withVariables(variables).build());

        //更新统一的流程实例
        uniWfService.wfSubmitCallbackByInst(task);

        //更新统一的待办列表
        uniWfService.wfSubmitCallbackByTask(task,uniwfWorkList);

        JSONObject resultData=WFResultUtil.success("流程提交成功");
        resultData.put("curstep","");

        return resultData;
    }

    @Override
    public String wfGoto(JSONObject et) { //主3

        //源任务标识
        String sourceTaskId=et.getString("sourcetaskid");

        //目标任务标识
        String targetTaskId=et.getString("targettaskid");

        if(StringUtils.isEmpty(sourceTaskId) || StringUtils.isEmpty(targetTaskId)){
            return "参数输入错误，请求参数中需包含 源任务标识：[sourcetaskid] 与 目标任务标识：[targettaskid]";
        }

        //执行流程跳转操作
        wfGoToUtil.jump(sourceTaskId,targetTaskId);

        return "流程跳转成功";
    }

    @Override
    public JSONObject wfClose(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs("system");

        //流程实例标识
        JSONObject uniwfWorkList=et.getJSONObject("wfworklist");

        JSONObject uniwfInstance=et.getJSONObject("wfinstance");

        if(ObjectUtils.isEmpty(uniwfWorkList) || ObjectUtils.isEmpty(uniwfInstance) )
            return  WFResultUtil.error("参数输入错误，请求参数中需包含 [wfworklist]、[wfinstance]") ;

        String instanceId=uniwfInstance.getString("wfengineinstanceid");

        if(StringUtils.isEmpty(instanceId))
            return  WFResultUtil.error("无法获取到[instanceId]参数值") ;

        //停止流程实例
        processRuntime.suspend(ProcessPayloadBuilder.suspend(instanceId));

        //更新统一的流程实例
        uniWfService.wfCloseCallbackByInst(instanceId);

        //更新统一的待办列表
        uniWfService.wfCloseCallbackByTask(instanceId);

        return WFResultUtil.success("流程成功中止");

    }

    @Override
    public String wfRestart(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs("system");

        //流程实例标识
        String instanceid=et.getString("instanceid");

        if(StringUtils.isEmpty(instanceid))
            return "参数输入错误，请求参数中需包含 [instanceid]";

        //恢复流程实例
        processRuntime.resume(ProcessPayloadBuilder.resume(instanceid));

        return "成功恢复流程";

    }

    @Override
    public String wfRollback(JSONObject et) {

        //流程实例标识
        String instanceid =et.getString("instanceid");

        if(StringUtils.isEmpty(instanceid) ){
            return "参数输入错误，请求参数中需包含 当前流程步骤标识：[instanceid]";
        }

        //当前任务
        org.activiti.engine.task.Task curTask = taskService.createTaskQuery().processInstanceId(instanceid).singleResult();

        //前一步任务
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceid).orderByTaskCreateTime().desc().list();

        if(ObjectUtils.isEmpty(historicTaskInstances) || historicTaskInstances.size()<2)
            return "历史步骤不存在，不允许退回";

        HistoricTaskInstance hisTaskInst=historicTaskInstances.get(1);

        org.activiti.engine.task.Task hisTask=wfGoToUtil.historicTask2Task(hisTaskInst);

        //将流程退回到上一步骤
        wfGoToUtil.jump(curTask,hisTask);

        return "流程撤回成功";

    }

    @Override
    public String wfSendBack(JSONObject et) {//主1

        //流程实例标识
        String instanceid =et.getString("instanceid");

        if(StringUtils.isEmpty(instanceid) ){
            return "参数输入错误，请求参数中需包含 当前流程步骤标识：[instanceid]";
        }

        //当前任务
        org.activiti.engine.task.Task curTask = taskService.createTaskQuery().processInstanceId(instanceid).singleResult();

        //前一步任务
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceid).orderByTaskCreateTime().desc().list();

        if(ObjectUtils.isEmpty(historicTaskInstances) || historicTaskInstances.size()<2)
            return "流程退回失败，未能正常查询到前一步流程信息";

        HistoricTaskInstance hisTaskInst=historicTaskInstances.get(1);

        org.activiti.engine.task.Task hisTask=wfGoToUtil.historicTask2Task(hisTaskInst);

        //将流程退回到上一步骤
        wfGoToUtil.jump(curTask,hisTask);

        return "流程退回成功";

    }

    @Override
    public String wfReassign(JSONObject et) {

        //任务标识
        String taskId=et.getString("taskid");

        //旧任务审批
        String old_assign=et.getString("old_assign");

        //新任务审批人
        String new_assign=et.getString("new_assign");

        if(StringUtils.isEmpty(taskId) ||  StringUtils.isEmpty(old_assign) || StringUtils.isEmpty(new_assign) )
            return "参数输入错误，请求参数中需包含 [taskid]、[old_assign]、[new_assign] ";

        //移除旧任务审批人
        taskService.deleteCandidateUser(taskId,old_assign);

        //添加新任务审批人
        taskService.addCandidateUser(taskId,new_assign);

        return "重置审批人员成功";
    }

    @Override
    public void wfMarkRead(JSONObject et) {
        //暂未实现
    }

    @Override
    public JSONObject wfDeploy(JSONObject et) {

        String systemId=et.getString("serviceid"); //系统标识

        String wfId=et.getString("wfid"); //工作流标识

        String wfName=et.getString("wfname");//工作流名称

        String wfverId=et.getString("wfverid"); //工作流版本

        String fileName=et.getString("filename"); //工作流文件名

        byte[] fileContent=et.getBytes("filecontent");//工作流文件内容 bpmn

        if( StringUtils.isEmpty(systemId) ||  StringUtils.isEmpty(wfId)  ||  StringUtils.isEmpty(wfverId) || ObjectUtils.isEmpty(fileContent ) )
            WFResultUtil.error(String.format("部署 [%s|%s|%s|%s] 流程发生错误，参数 [serviceId]、[wfid]、[wfverid]、[fileName] 值不允许为空",systemId,wfId,wfName,wfverId));

        List<Deployment> hisDeploy= repositoryService.createDeploymentQuery().deploymentTenantId(systemId).deploymentKey(wfId).deploymentCategory(wfverId).list();

        if(hisDeploy.size()>0){
            String deployId = hisDeploy.get(0).getId();
            JSONObject resultData =WFResultUtil.success(String.format("系统 [%s] 流程 [%s|%s|%s] 已经部署，引擎将忽略当前部署请求",systemId,wfId,wfName,wfverId));
            resultData.put("deployid",deployId);
            return  resultData;
        }

        Deployment deploy = repositoryService.createDeployment().addBytes(fileName,fileContent).key(wfId).name(wfName).tenantId(systemId).category(wfverId).deploy();

        JSONObject resultData =WFResultUtil.success("部署成功");

        resultData.put("deployid",deploy.getId());

        return resultData;
    }


    @Override
    public List<Task> getWFCurStep(JSONObject et) {

        //模拟用户登录
        securityUtil.logInAs("system");

        List<Task> tasks =null;

        //查询当前用户的待办
        Page<Task> p_tasks=taskRuntime.tasks(Pageable.of(0,Short.MAX_VALUE),TaskPayloadBuilder.tasks().build());

        if (p_tasks == null || p_tasks.getTotalItems()==0) {
            System.out.println("当前流程没有相关任务");
            System.out.println("*****************************************************************************");
            return tasks;
        }

        tasks=p_tasks.getContent();

        return tasks;
    }

    @Override
    public List<Task> getWFHisStep(JSONObject et) {

        //流程实例
        String instanceid = et.getString("instanceid");

        if (StringUtils.isEmpty(instanceid)) {
            return null;
        }

        //查询用户历史任务
        List tasks=historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceid).list();

        if (tasks == null || tasks.size()==0) {
            System.out.println("当前流程没有相关任务");
            System.out.println("流程实例ID:" + instanceid);
            System.out.println("*****************************************************************************");
            return null;
        }

        return tasks;
    }

    @Override
    public List<SequenceFlow> getWFNextStep(JSONObject et) {

        String instanceid=et.getString("instanceid");

        if(StringUtils.isEmpty(instanceid) ){
            return null;
        }

        //查询当前任务
        org.activiti.engine.task.Task task = taskService.createTaskQuery().processInstanceId(instanceid).singleResult();

        if(ObjectUtils.isEmpty(task))
            return null;
        else
            return wfGoToUtil.getNextFlows(task);
    }

    /**
    * 填充流程参数
    * @param et
    * @return
    */
    private Map<String, Object> getVariables(JSONObject et) {

        Map<String, Object> instanceVariables = new HashMap<>();

        JSONObject variables = et.getJSONObject("variables");

        JSONObject wfworklist = et.getJSONObject("wfworklist");

        JSONObject wfinstance = et.getJSONObject("wfinstance");

        if (!ObjectUtils.isEmpty(variables)) {
            instanceVariables.putAll(variables);
        }
        if (!ObjectUtils.isEmpty(wfworklist)) {
            instanceVariables.putAll(wfworklist);
        }
        if (!ObjectUtils.isEmpty(wfinstance)) {
            instanceVariables.putAll(wfinstance);
        }
        return instanceVariables;
    }

}
