package com.ho.flow.workOrder;

import cn.hutool.core.date.DateUtil;
import com.ho.flow.vo.resp.workorder.FallBackTaskResp;
import com.ho.flow.vo.resp.workorder.HisTaskResp;
import org.activiti.bpmn.constants.BpmnXMLConstants;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.Process;
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.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.util.ExecutionGraphUtil;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author fancl
 * @desc: 工单处理流程
 * @date 2023/1/2
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class ProcInstWorkOrderDemo {
    @Autowired
    RepositoryService repositoryService;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    TaskService taskService;

    @Autowired
    HistoryService historyService;

    /**
     * 测试根据流程id和历史人物id单cha
     */
    @Test
    public void getHisOne(){



        List<Task> candidateTaskList = taskService.createTaskQuery()
                //.processVariableValueEquals(WorkOrderConstant.orderType, "workOrder")
                .taskTenantId("1")
                //候选人有自己的
                .taskCandidateUser("1612651850309062656")
                .list();
        System.out.println();
    }

    /**
     * 回退到某个节点
     */
    @Test
    public void testFallback(){

        List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId("542501")
                .finished()
                .orderByHistoricActivityInstanceEndTime().asc().list();
        // 可回退任务节点列表
        List<String> activityIdList = activityInstanceList.stream()
                // 仅获取 开始节点 和 用户任务节点
                .filter(activityInstance -> BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType()))
                .map(HistoricActivityInstance::getActivityId)
                //过滤掉每个节点
                .distinct()
                .collect(Collectors.toList());

        Task task = taskService.createTaskQuery().taskId("547530").singleResult();
        if (task == null){
            return ;
        }
        // 任务定义key 等于 当前任务节点id
        String taskDefinitionKey = task.getTaskDefinitionKey();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        Process mainProcess = bpmnModel.getMainProcess();
        // 当前节点
        FlowNode currentFlowNode = (FlowNode) mainProcess.getFlowElement(taskDefinitionKey, true);

            // 回退到主流程的节点
            FlowNode lastFlowNode = (FlowNode) mainProcess.getFlowElement("d1", true);
            // 判断 【工具类判断是否可以从源节点 到 目标节点】
            Set<String> set = new HashSet<>();
            if (lastFlowNode != null && ExecutionGraphUtil.isReachable(mainProcess,lastFlowNode,currentFlowNode, set)) {
                System.out.println();
                //  临时保存当前活动的原始方向
                List<SequenceFlow> originalSequenceFlowList = new ArrayList<>();
                originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
                //  清理活动方向
                currentFlowNode.getOutgoingFlows().clear();

                //  建立新方向
                SequenceFlow newSequenceFlow = new SequenceFlow();
                newSequenceFlow.setId("newSequenceFlowId");
                newSequenceFlow.setSourceFlowElement(currentFlowNode);
                newSequenceFlow.setTargetFlowElement(lastFlowNode);
                List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
                newSequenceFlowList.add(newSequenceFlow);
                //  当前节点指向新的方向
                currentFlowNode.setOutgoingFlows(newSequenceFlowList);

                //  完成当前任务
                taskService.complete(task.getId());

                //  重新查询当前任务
                Task nextTask = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
                if (null != nextTask) {
                    taskService.setAssignee(nextTask.getId(), "1");
                }

                //  恢复原始方向
                currentFlowNode.setOutgoingFlows(originalSequenceFlowList);

        }

    }

    /**
     * 获取已完成节点的信息
     */
    @Test
    public void testGetHistoryNode(){
        String processId = "612882";
        //创建返回对象
        List<HisTaskResp> hisTaskRespList = new ArrayList<>();
        //获取所有历史节点任务
        List<HistoricTaskInstance> historicTaskInstanceList11 = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processId)
                .orderByHistoricTaskInstanceStartTime().asc().list();

        Integer count = 1;
        //循环遍历赋值
        for (HistoricTaskInstance historicTaskInstance : historicTaskInstanceList11) {
            count++;
        }

        System.out.println(hisTaskRespList);
        // 获取传入的当前任务id
        String taskId = "555009";
        //获取所有历史节点任务
        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId("542501")
                .orderByHistoricTaskInstanceStartTime().asc().list();

        //先查这个任务
        Task task = taskService.createTaskQuery()
                //用任务id查询
                .taskId(taskId)
                //集团id
                .taskTenantId("1")
                //要使用责任人查询, 避免去做别人的任务
                //.taskAssignee(taskReq.getAssigneeUser())
                .singleResult();

        String taskDefinitionKey = task.getTaskDefinitionKey();
        //获取当前任务节点的数字
        String substring = taskDefinitionKey.substring(1);
        Integer currentNumber = Integer.valueOf(substring);

        Map<String, List<HistoricTaskInstance>> hisTaskMap = historicTaskInstanceList.stream()
                //过滤当前任务以后的节点
                .filter(s -> {
                    String number = s.getTaskDefinitionKey().substring(1);
                    Integer integer = Integer.valueOf(number);
                    return currentNumber > integer;
                }).collect(Collectors.groupingBy(HistoricTaskInstance::getName));
        List<FallBackTaskResp> fallBackTaskRespList = new ArrayList<>();
        for (String key : hisTaskMap.keySet()) {
            List<HistoricTaskInstance> historicTaskInstances = hisTaskMap.get(key);
            FallBackTaskResp resp = new FallBackTaskResp();
            resp.setName(key);
            List<String> taskInstIds = new ArrayList<>();
            for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {
                taskInstIds.add(historicTaskInstance.getId());
            }
            resp.setTaskInstIds(taskInstIds);
            fallBackTaskRespList.add(resp);
        }
        System.out.println(fallBackTaskRespList);
        }


    /**
     * 发布流程 流程部署
     */
    @Test
    public void initDeployment() {
        String fileName = "processes/workOrder.bpmn20.xml";
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource(fileName)
                .name("工单流程")
                .tenantId("208")
                //.category("workOrder")
                .deploy();
        System.out.println("流程部署名称：" + deployment.getName() + " key: " + deployment.getKey() + " id:" + deployment.getId());
    }

    /**
     * 创建流程实例
     */
    @Test
    public void initProcessInstance() {
        // 流程定义KEY
        String processDefinitionKey = "workOrder";
        // 业务表KEY（用于把业务数据与Activiti7流程数据相关联） 实际可以为工单号
        String businessKey = "4208169753200945";

        // 参数
        Map<String, Object> variables = new HashMap<>(16);
        //可以查到这个工单的组织机构列表
        variables.put("stationId","251");
        //类型
        variables.put("assignType","workOrder");
        //设置候选人,因为是多个,使用集合
        List<String> toUsers = Arrays.asList("toUsers", "fan,lisi");
        variables.put("toUsers", toUsers);

        //租户id,使用集团id
        String tenantId = "1";
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceByKeyAndTenantId(processDefinitionKey,businessKey, variables,tenantId);
        System.out.println("流程实例ID：" + processInstance.getProcessInstanceId());
        System.out.println("业务businesKey：" + processInstance.getBusinessKey());
    }

    //查询历史记录
    @Test
    public void queryTaskHistoryByProcInst(){
        String procInstId = "285001";
        List<HistoricTaskInstance> procInstList = historyService.createHistoricTaskInstanceQuery().processInstanceId(procInstId)
                .orderByHistoricTaskInstanceStartTime().asc().list();
        for (HistoricTaskInstance hti : procInstList) {
            System.out.println("历史任务ID：" + hti.getId());
            System.out.println("流程定义ID：" + hti.getProcessDefinitionId());
            System.out.println("流程执行实例ID：" + hti.getExecutionId());
            System.out.println("流程结束时间：" + DateUtil.format(hti.getEndTime(), "yyyy-MM-dd HH:mm:ss"));
            System.out.println("流程的处理人是：" + hti.getAssignee());
            System.out.println("################################");
        }
    }

    /**
     * 查询流程部署列表
     */
    @Test
    public void listDeployments() {
        List<Deployment> deployments = repositoryService.createDeploymentQuery()
                .deploymentKey("order2").deploymentTenantId("1").list();
        if (!deployments.isEmpty()) {
            deployments.forEach(deployment -> {
                System.out.println("Id：" + deployment.getId());
                System.out.println("Name：" + deployment.getName());
                System.out.println("DeploymentTime：" + deployment.getDeploymentTime());
                System.out.println("Key：" + deployment.getKey());
            });
        }
    }

    /**
     * 删除对流程实例、历史流程实例和作业的给定部署和级联删除
     */
    @Test
    public void deleteDeployment() {
        String deploymentId = "562501";
        this.repositoryService.deleteDeployment(deploymentId, true);
    }

    @Test
    public void deleteProcInst(){
        String procInstId = "537618";
        runtimeService.deleteProcessInstance(procInstId,"用不到了");
    }



    //删除部署的任务
    @Test
    public void deleteDeployedProcess() {
        List<String> list = Arrays.asList("147501", "150001", "155001", "172501");
        String deployId1 = "142501";
        for (String s : list) {
            repositoryService.deleteDeployment(s, true);
        }
        repositoryService.deleteDeployment(deployId1, true);
    }


}
