package com.codvision.workflow.listener;


import com.codvision.cachecore.utils.RedisUtil;
import com.codvision.workflow.entity.WorkFlowData;
import com.codvision.workflow.service.WorkFlowDataService;
import com.codvision.workflow.util.WorkFlowUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
import org.flowable.engine.delegate.event.FlowableActivityEvent;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.codvision.workflow.constant.CacheContant.WORK_FLOW_STATUS;
import static com.codvision.workflow.constant.WorkFlowConstant.EXTENSION_ELEMENT_WORK_FLOW_STATUS;
import static com.codvision.workflow.constant.WorkFlowConstant.EXTENSION_ELEMENT_WORK_FLOW_STATUS_CODE;

/**
 * 全局流程状态更改监听器
 * @author hxl
 */
@Component
@RequiredArgsConstructor
public class GlobalWorkFlowStatusChangeListener extends AbstractFlowableEngineEventListener  {

    private final RepositoryService repositoryService;
    private final WorkFlowDataService workFlowDataService;

    @Override
    protected void activityCompleted(FlowableActivityEvent event) {
        if (!BpmnXMLConstants.ELEMENT_EVENT_END.equals(event.getActivityType())) {
            return;
        }

        changeStatus(event.getProcessDefinitionId(), event.getProcessInstanceId(), event.getActivityId());
    }

    @Override
    protected void taskCreated(FlowableEngineEntityEvent event) {
        TaskEntityImpl entity = (TaskEntityImpl) event.getEntity();
        changeStatus(entity.getProcessDefinitionId(), entity.getProcessInstanceId(), entity.getTaskDefinitionKey());
    }


    private void changeStatus(String processDefinitionId, String instanceId, String flowElementId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        FlowElement flowElement = WorkFlowUtil.getFlowElementById(bpmnModel, flowElementId);
        if (flowElement == null) {
            return;
        }

        List<ExtensionElement> flowStatusElements = WorkFlowUtil.getExtensionElements(flowElement, EXTENSION_ELEMENT_WORK_FLOW_STATUS);
        if (CollectionUtils.isEmpty(flowStatusElements)) {
            return;
        }

        ExtensionElement extensionElement = flowStatusElements.get(0);
        String workFlowStatus = extensionElement.getAttributeValue(null, EXTENSION_ELEMENT_WORK_FLOW_STATUS_CODE);
        if (StringUtils.isBlank(workFlowStatus)) {
            return;
        }

        WorkFlowData workFlowData = workFlowDataService.getFormDataByInstanceId(instanceId);
        if (workFlowData == null) {
            // 启动时数据还未存储入库，此时先记录流程状态
            RedisUtil.set(WORK_FLOW_STATUS + instanceId, workFlowStatus,1, TimeUnit.MINUTES);
            return;
        }

        workFlowData.setStatus(Integer.valueOf(workFlowStatus));
        workFlowDataService.updateById(workFlowData);
    }
}
