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

import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;

import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ASSIGNEE_SKIP_FLAT;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_ROBOT;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.DUMMY_TASK_NOT_EXISTS;

/**
 * 自定义的完成虚拟任务命令实现
 *
 * @author wangli
 * @since 2023/12/27 11:24
 */
public class CustomCompleteDummyTaskCmd implements Command<Void>, Serializable {
    private final String processInstanceId;
    private final String taskId;
    private final String flowNodeName;
    private final String operationDesc;
    private final ExtAxHiTaskInstService extAxHiTaskInstService;

    public CustomCompleteDummyTaskCmd(String processInstanceId, String taskId, String flowNodeName,
                                      String operationDesc, ExtAxHiTaskInstService extAxHiTaskInstService) {
        this.processInstanceId = processInstanceId;
        this.taskId = taskId;
        this.flowNodeName = flowNodeName;
        this.operationDesc = operationDesc;
        this.extAxHiTaskInstService = extAxHiTaskInstService;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);

        TaskService taskService = processEngineConfiguration.getTaskService();
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId)
                .taskId(taskId).singleResult();
        if (Objects.isNull(task)) {
            throw new WorkflowEngineException(DUMMY_TASK_NOT_EXISTS, processInstanceId, taskId);
        }
        task.setName(flowNodeName);
        taskService.saveTask(task);

        Authentication.setAuthenticatedUserId("system");
        CustomTaskHelper.addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc);
        Authentication.setAuthenticatedUserId(null);

        taskService.complete(task.getId());

        continueProcessingTask(commandContext);

        CustomTaskHelper.createExtTaskInst(extAxHiTaskInstService, processInstanceId, task.getId(),
                NODE_ROBOT.getType(), BpmnTaskDelegateAssigner.buildDummyAssigner("system",
                        TASK_ASSIGNEE_SKIP_FLAT, "系统"), BpmnProcessInstanceResultEnum.APPROVED.getStatus());
        return null;
    }

    private void continueProcessingTask(CommandContext commandContext) {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        TaskService taskService = processEngineConfiguration.getTaskService();
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();
        if (CollectionUtils.isEmpty(taskList)) {
            return;
        }
        taskList.stream().filter(i -> !Objects.equals(i.getTaskDefinitionKey(), NODE_ROBOT.getType()))
                .filter(i -> Objects.nonNull(i.getOwner()))
                .forEach(i -> {
                    taskService.setAssignee(i.getId(), i.getOwner());
                    taskService.setOwner(i.getId(), null);
                });
    }
}
