package org.springblade.flow.base.util;

import cn.hutool.core.util.ObjectUtil;

import org.flowable.bpmn.model.*;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.RepositoryServiceImpl;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springblade.flow.engine.custom.constants.GlobalProcessVariableConstants;
import org.springblade.flow.engine.enums.FlowTaskStatusEnum;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author LoveMyOrange
 * @create 2022-01-06 14:13
 */
@Component
public class ActivitiUtils {

    @Resource
    private HistoryService historyService;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;

    public List<String> getNextNode(String processDefinitionId,String currentActivity){
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        FlowElement flowElement = bpmnModel.getMainProcess().getFlowElement(currentActivity);
        List<String> nodeNextList = new ArrayList<>();
        getNextNode(nodeNextList,flowElement);
        return nodeNextList;
    }

    private void getNextNode(List<String> nodeNextList,FlowElement flowElement){
        if(flowElement instanceof Task){
            Task task=(Task) flowElement;
            nodeNextList.add(task.getId());
        }
        else if(flowElement instanceof Gateway){
            Gateway gateway =(Gateway)flowElement;
            List<SequenceFlow> outgoingFlows = gateway.getOutgoingFlows();
            for (SequenceFlow outgoingFlow : outgoingFlows) {
                FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement();
                getNextNode(nodeNextList,targetFlowElement);
            }
        }
    }
    /**
     * 通过流程定义id 获取 流程定义实体对象
     * @param processDefinitionId
     * @return
     */
    public ProcessDefinitionEntity getProcessDefinitionEntityById(String processDefinitionId){
        return (ProcessDefinitionEntity) ((RepositoryServiceImpl)repositoryService).getDeployedProcessDefinition(processDefinitionId);
    }

    /**
     * 判断流程状态
     * @param processInstanceId
     * @return
     */
    public Boolean checkStatus(String processInstanceId){
        HistoricVariableInstance historicVariableInstance = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).variableName(GlobalProcessVariableConstants.PROCESS_STATUS).singleResult();
        Integer status = (Integer) historicVariableInstance.getValue();
        if(ObjectUtil.equal(status, FlowTaskStatusEnum.Draft.getCode())
          || ObjectUtil.equal(status, FlowTaskStatusEnum.Reject.getCode())
          || ObjectUtil.equal(status, FlowTaskStatusEnum.Revoke.getCode())
        ){
              return true;
        }
        else{
            return false;
        }

    }

    /**
     * 通过流程实例id或者 业务主键 或者 任务id 获取流程实例
     * @param id
     * @return
     */
    public ProcessInstance getProcessInstanceByIdOrBusinessKey(String id){
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult();
        if(processInstance==null){
            processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(id).singleResult();
            if(processInstance==null){
                HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(id).singleResult();
                return runtimeService.createProcessInstanceQuery().processInstanceId(historicTaskInstance.getProcessInstanceId()).singleResult();
            }
        }
        return processInstance;
    }

    public HistoricProcessInstance getHistoricProcessInstanceByIdOrBusinessKeyOrTaskId(String id){
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult();
        if(historicProcessInstance==null){
            historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(id).includeProcessVariables().singleResult();
            if(historicProcessInstance==null){
                HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(id).singleResult();
                return historyService.createHistoricProcessInstanceQuery().processInstanceId(historicTaskInstance.getProcessInstanceId()).includeProcessVariables().singleResult();
            }
        }
        return historicProcessInstance;
    }
}
