package cn.axzo.workflow.server.controller.listener.task;

import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventProducer;
import cn.axzo.workflow.common.enums.ProcessTaskEventEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.model.response.mq.ProcessTaskDTO;
import cn.axzo.workflow.core.listener.BpmnTaskEventListener;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT;
import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_ASSIGNED;
import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_COMPLETED;
import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_CREATED;
import static cn.axzo.workflow.common.enums.ProcessTaskEventEnum.PROCESS_TASK_DELETED;


/**
 * 流程任务的 MQ 发送监听
 *
 * @author wangli
 * @since 2023/7/10 18:22
 */
@Slf4j
@Component
public class RocketMqBpmnTaskEventListener implements BpmnTaskEventListener, Ordered {

    @Resource
    private EventProducer<?> eventProducer;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private RepositoryService repositoryService;

    @Override
    public void onCreated(DelegateTask delegateTask) {
        if (log.isDebugEnabled()) {
            log.debug("task created event");
        }
        ProcessTaskDTO dto = build(delegateTask, PROCESS_TASK_CREATED);
        log.info("RocketMqBpmTaskEventListener#onCreated MQ.Data: {}", com.alibaba.fastjson.JSON.toJSONString(dto));
        sendMessageQueue(dto, PROCESS_TASK_CREATED);
    }

    @Override
    public void onAssigned(DelegateTask delegateTask) {
        if (log.isDebugEnabled()) {
            log.debug("task assigned event");
        }
        ProcessTaskDTO dto = build(delegateTask, PROCESS_TASK_ASSIGNED);
        log.info("RocketMqBpmTaskEventListener#onAssigned MQ.Data: {}", com.alibaba.fastjson.JSON.toJSONString(dto));
        sendMessageQueue(dto, PROCESS_TASK_ASSIGNED);
    }

    @Override
    public void onCompleted(DelegateTask delegateTask) {
        if (log.isDebugEnabled()) {
            log.debug("task completed event");
        }
        ProcessTaskDTO dto = build(delegateTask, PROCESS_TASK_COMPLETED);
        log.info("RocketMqBpmTaskEventListener#onCompleted MQ.Data: {}", com.alibaba.fastjson.JSON.toJSONString(dto));
        sendMessageQueue(dto, PROCESS_TASK_COMPLETED);
    }

    @Override
    public void onDeleted(DelegateTask delegateTask) {
        if (log.isDebugEnabled()) {
            log.debug("task deleted event");
        }
        ProcessTaskDTO dto = build(delegateTask, PROCESS_TASK_DELETED);
        log.info("RocketMqBpmTaskEventListener#onDeleted MQ.Data: {}", com.alibaba.fastjson.JSON.toJSONString(dto));
        sendMessageQueue(dto, PROCESS_TASK_DELETED);
    }

    private Deployment getDeployment(String processInstanceId) {
        ProcessInstance processInstance =
                runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        return repositoryService.createDeploymentQuery().deploymentId(processInstance.getDeploymentId()).singleResult();
    }

    public ProcessTaskDTO build(DelegateTask delegateTask, ProcessTaskEventEnum type) {
        return new ProcessTaskDTO()
                .setType(type)
                .setCategory(getDeployment(delegateTask.getProcessInstanceId()).getCategory())
                .setProcessTaskId(delegateTask.getId())
                .setProcessInstanceId(delegateTask.getProcessInstanceId())
                .setCurrentElementKey(delegateTask.getTaskDefinitionKey())
                .setCurrentElementName(delegateTask.getName())
                .setProcessDefinitionId(delegateTask.getProcessDefinitionId())
                .setInitiator(delegateTask.getVariable(INTERNAL_INITIATOR, BpmnTaskDelegateAssigner.class))
                .setApprover(delegateTask.getVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + delegateTask.getId(), BpmnTaskDelegateAssigner.class))
                .setVariables(delegateTask.getVariables())
                .setStartTime(delegateTask.getCreateTime())
                .setTenantId(delegateTask.getTenantId());
    }

    public void sendMessageQueue(ProcessTaskDTO dto, ProcessTaskEventEnum eventEnum) {
        eventProducer.send(Event.builder()
                .shardingKey(dto.getProcessTaskId())
                .eventCode(eventEnum.getEventCode())
                .targetId(dto.getProcessTaskId())
                .targetType(eventEnum.getTag())
                .data(dto)
                .build());
    }

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE + 1;
    }
}
