package cn.axzo.workflow.core.engine.behavior;

import cn.axzo.workflow.core.engine.event.ExtTaskInstCreateEvent;
import cn.axzo.workflow.core.engine.event.ExtTaskInstUpdateEvent;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.ReceiveTask;
import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.bpmn.behavior.ReceiveTaskActivityBehavior;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.TaskHelper;
import org.flowable.task.service.TaskService;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;

import java.util.Objects;

import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;

/**
 * 自定义 ReceiveTask 行为
 *
 * @author wangli
 * @since 2023/11/23 14:41
 */
@Slf4j
public class CustomReceiveTaskActivityBehavior extends ReceiveTaskActivityBehavior {
    protected ReceiveTask receiveTask;

    public CustomReceiveTaskActivityBehavior(ReceiveTask receiveTask) {
        this.receiveTask = receiveTask;
    }

    @Override
    public void execute(DelegateExecution execution) {
        super.execute(execution);
        // 记录task表, 可被审批记录检索到
        CommandContext commandContext = CommandContextUtil.getCommandContext();
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService();
        TaskEntity task = taskService.createTask();
        task.setExecutionId(execution.getId());
        task.setTaskDefinitionKey(receiveTask.getId());
        task.setPropagatedStageInstanceId(execution.getPropagatedStageInstanceId());
        task.setName(receiveTask.getName());
        TaskHelper.insertTask(task, (ExecutionEntity) execution, true, false);


        // 添加 taskInst 扩展表数据
        FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher();
        eventDispatcher.dispatchEvent(new ExtTaskInstCreateEvent(execution.getProcessInstanceId(),
                        execution.getCurrentActivityId(), task.getId(), PROCESSING),
                processEngineConfiguration.getEngineCfgKey());
    }

    @Override
    public void leave(DelegateExecution execution) {
        CommandContext commandContext = CommandContextUtil.getCommandContext();
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        FlowableEventDispatcher eventDispatcher = processEngineConfiguration.getEventDispatcher();

        org.flowable.engine.TaskService taskService = processEngineConfiguration.getTaskService();
        TaskEntity task = (TaskEntity) taskService.createTaskQuery().executionId(execution.getId())
                .taskDefinitionKey(execution.getCurrentActivityId()).singleResult();
        if (Objects.nonNull(task)) {
            // 用于新版日志
            task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), APPROVED.getStatus());

            eventDispatcher.dispatchEvent(new ExtTaskInstUpdateEvent(execution.getProcessInstanceId(),
                            receiveTask.getId(), task.getId(), APPROVED),
                    processEngineConfiguration.getEngineCfgKey());

            // 解决两个业务节点相邻时，无法正确的往下流转的问题
            TaskHelper.deleteTask(task, "complete business node", false, true, true);
        } else {
            log.warn("ReceiveTask is null, executionId: {}, activityId: {}", execution.getId(),
                    execution.getCurrentActivityId());
        }
        super.leave(execution);
    }
}
