package cn.datax.service.workflow.service.impl;

import cn.datax.common.utils.SecurityUtil;
import cn.datax.service.workflow.api.dto.ProcessInstanceCreateRequest;
import cn.datax.service.workflow.api.query.FlowInstanceQuery;
import cn.datax.service.workflow.api.vo.FlowInstanceVo;
import cn.datax.service.workflow.service.FlowInstanceService;
import cn.datax.service.workflow.utils.BeanCopyUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.BpmnModel;
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.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceBuilder;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class FlowInstanceServiceImpl implements FlowInstanceService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RepositoryService repositoryService;

    private static final String IMAGE_TYPE = "png";
    private static final String FONT_NAME = "宋体";

    @Override
    public Page<FlowInstanceVo> page(FlowInstanceQuery flowInstanceQuery) {
        ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
        if(StrUtil.isNotBlank(flowInstanceQuery.getName())){
            processInstanceQuery.processInstanceNameLike(flowInstanceQuery.getName());
        }
        long count = processInstanceQuery.count();
        List<ProcessInstance> processInstanceList = processInstanceQuery.orderByStartTime().desc().listPage((flowInstanceQuery.getPageNum() - 1) * flowInstanceQuery.getPageSize(), flowInstanceQuery.getPageSize());
        List<FlowInstanceVo> flowInstanceVoList = BeanCopyUtil.copyListProperties(processInstanceList, FlowInstanceVo::new);
        Page<FlowInstanceVo> page = new Page<>(flowInstanceQuery.getPageNum(), flowInstanceQuery.getPageSize());
        page.setRecords(flowInstanceVoList);
        page.setTotal(count);
        return page;
    }

    @Override
    public void activateProcessInstanceById(String processInstanceId) {
        log.info("成功激活流程实例ID:{}", processInstanceId);
        runtimeService.activateProcessInstanceById(processInstanceId);
    }

    @Override
    public void suspendProcessInstanceById(String processInstanceId) {
        log.info("成功挂起流程实例ID:{}", processInstanceId);
        runtimeService.suspendProcessInstanceById(processInstanceId);
    }

    @Override
    public void deleteProcessInstance(String processInstanceId, String deleteReason) {
        log.info("成功删除流程实例ID:{}", processInstanceId);
        runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
    }

    @Override
    public void startProcessInstanceById(ProcessInstanceCreateRequest request) {
        Assert.notNull(request.getBusinessKey(), "请输入业务id");
        Assert.notNull(request.getBusinessType(), "请输入业务类型");
        Assert.notNull(request.getProcessDefinitionId(), "请输入流程定义ID");
        ProcessInstanceBuilder processInstanceBuilder = runtimeService.createProcessInstanceBuilder();
        if(StrUtil.isNotBlank(request.getProcessDefinitionId())){
            processInstanceBuilder.processDefinitionId(request.getProcessDefinitionId());
        }
        if(StrUtil.isNotBlank(request.getBusinessKey())){
            processInstanceBuilder.businessKey(request.getBusinessKey());
        }
        processInstanceBuilder.variables(request.getVariables());
        // 流程实例标题(动态拼接)
        if(StrUtil.isNotBlank(request.getBusinessName())){
            processInstanceBuilder.name(request.getBusinessName());
        }
        Authentication.setAuthenticatedUserId(SecurityUtil.getUserId());
        ProcessInstance processInstance = processInstanceBuilder.start();
        Authentication.setAuthenticatedUserId(null);
        log.info("发起流程成功，流程ID:{}", processInstance.getId());
    }

    @Override
    public InputStream createImage(String processInstanceId) {
        //1.获取当前的流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = null;
        List<String> activeActivityIds = new ArrayList<>();
        List<String> highLightedFlows = new ArrayList<>();
        //2.获取所有的历史轨迹线对象
        List<HistoricActivityInstance> historicSquenceFlows = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId).activityType(BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW).list();
        historicSquenceFlows.forEach(historicActivityInstance -> highLightedFlows.add(historicActivityInstance.getActivityId()));
        //3.获取流程定义id和高亮的节点id
        if (processInstance != null) {
            //3.1.正在运行的流程实例
            processDefinitionId = processInstance.getProcessDefinitionId();
            activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId);
        } else {
            //3.2.已经结束的流程实例
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();
            //3.3.获取结束节点列表
            List<HistoricActivityInstance> historicEnds = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(processInstanceId).activityType(BpmnXMLConstants.ELEMENT_EVENT_END).list();
            List<String> finalActiveActivityIds = activeActivityIds;
            historicEnds.forEach(historicActivityInstance -> finalActiveActivityIds.add(historicActivityInstance.getActivityId()));
        }
        //4.获取bpmnModel对象
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        //5.生成图片流
        DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
        InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, IMAGE_TYPE, activeActivityIds,
                highLightedFlows, FONT_NAME, FONT_NAME, FONT_NAME,
                null, 1.0, true);
        return inputStream;
    }

    @Override
    public void stopProcessInstanceById(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance != null) {
            //1、添加终止意见
            //2、执行终止
        }
    }

    @Override
    public void pageMyStartedProcessInstance(FlowInstanceQuery flowInstanceQuery) {
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
        historicProcessInstanceQuery.startedBy(SecurityUtil.getUserId());
        long count = historicProcessInstanceQuery.count();
        List<HistoricProcessInstance> historicProcessInstanceList = historicProcessInstanceQuery.orderByProcessInstanceStartTime().desc()
                .listPage((flowInstanceQuery.getPageNum() - 1) * flowInstanceQuery.getPageSize(), flowInstanceQuery.getPageSize());
    }

    @Override
    public void pageMyInvolvedProcessInstance(FlowInstanceQuery flowInstanceQuery) {
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
        historicProcessInstanceQuery.involvedUser(SecurityUtil.getUserId());
        long count = historicProcessInstanceQuery.count();
        List<HistoricProcessInstance> historicProcessInstanceList = historicProcessInstanceQuery.orderByProcessInstanceStartTime().desc()
                .listPage((flowInstanceQuery.getPageNum() - 1) * flowInstanceQuery.getPageSize(), flowInstanceQuery.getPageSize());
    }
}
