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.cfg.IdGenerator;
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.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.Date;
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.HIDDEN_ASSIGNEE_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE;
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_CANT_CREATED;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.DUMMY_TASK_CANT_REPEAT_CREATE;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.DUMMY_TASK_CREATED_ERROR;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.DUMMY_TASK_CREATED_NOT_SUPPORT;
import static org.flowable.task.api.Task.DEFAULT_PRIORITY;

/**
 * 自定义的创建虚拟任务命令实现
 *
 * @author wangli
 * @since 2023/12/27 10:21
 */
public class CustomCreateDummyTaskCmd implements Command<String>, Serializable {
    private final String processInstanceId;
    private final String flowNodeName;
    private final String operationDesc;
    private final BpmnTaskDelegateAssigner operator;
    private final ExtAxHiTaskInstService extAxHiTaskInstService;

    public CustomCreateDummyTaskCmd(String processInstanceId, String flowNodeName, String operationDesc,
                                    BpmnTaskDelegateAssigner operator, ExtAxHiTaskInstService extAxHiTaskInstService) {
        this.processInstanceId = processInstanceId;
        this.flowNodeName = flowNodeName;
        this.operationDesc = operationDesc;
        this.operator = operator;
        this.extAxHiTaskInstService = extAxHiTaskInstService;
    }

    /**
     * 在同一个实例下,不允许创建多个执行中的虚拟任务节点
     *
     * @param commandContext
     * @return
     */
    @Override
    public String execute(CommandContext commandContext) {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);

        HistoryService historyService = processEngineConfiguration.getHistoryService();

        HistoricProcessInstance processInstance =
                historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (Objects.isNull(processInstance)) {
            throw new WorkflowEngineException(DUMMY_TASK_CREATED_ERROR, processInstanceId);
        }
        if (!Objects.equals(processInstance.getBusinessStatus(),
                BpmnProcessInstanceResultEnum.PROCESSING.getStatus())) {
            throw new WorkflowEngineException(DUMMY_TASK_CREATED_NOT_SUPPORT, processInstanceId);
        }

        TaskService taskService = processEngineConfiguration.getTaskService();
        List<Task> activeTaskList = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();

        activeTaskList.stream().filter(task -> Objects.equals(task.getAssignee(), NO_ASSIGNEE)).findAny().ifPresent(task -> {
            throw new WorkflowEngineException(DUMMY_TASK_CANT_CREATED, processInstanceId);
        });
        activeTaskList.stream().filter(task -> Objects.equals(task.getTaskDefinitionKey(), NODE_ROBOT.getType())).findAny().ifPresent(task -> {
            throw new WorkflowEngineException(DUMMY_TASK_CANT_REPEAT_CREATE);
        });

        IdGenerator idGenerator = processEngineConfiguration.getIdGenerator();

        TaskEntity task = (TaskEntity) taskService.newTask(idGenerator.getNextId());
        task.setCategory(processInstance.getProcessDefinitionKey().split(":")[0]);
        task.setDescription(processInstance.getDescription());
        task.setTenantId(processInstance.getTenantId());
        // 已完成的审批,不能在此时设置审批人
        //        task.setAssignee(operator.buildAssigneeId());
        task.setName(flowNodeName);
        task.setProcessDefinitionId(processInstance.getProcessDefinitionId());
        task.setProcessInstanceId(processInstance.getId());
        task.setTaskDefinitionKey(NODE_ROBOT.getType());
        task.setPriority(DEFAULT_PRIORITY);
        task.setCreateTime(new Date());
        // 创建临时节点
        taskService.saveTask(task);

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

        if (Objects.nonNull(operator)) {
            CommandContextUtil.getEntityCache().findInCache(HistoricTaskInstanceEntity.class).stream()
                    .filter(i -> Objects.equals(i.getId(), task.getId())).findAny()
                    .ifPresent(i -> i.setAssignee(operator.buildAssigneeId()));
        }

        completeProcessingTask(commandContext);

        CustomTaskHelper.createExtTaskInst(extAxHiTaskInstService, processInstanceId, task.getId(),
                NODE_ROBOT.getType(),
                Objects.isNull(operator) ? BpmnTaskDelegateAssigner.buildDummyAssigner("system",
                        TASK_ASSIGNEE_SKIP_FLAT, "系统") : operator,
                BpmnProcessInstanceResultEnum.PROCESSING.getStatus());
        return task.getId();
    }

    private void completeProcessingTask(CommandContext commandContext) {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        TaskService taskService = processEngineConfiguration.getTaskService();
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();
        if (!CollectionUtils.isEmpty(taskList)) {
            taskList.forEach(i -> {
                taskService.setOwner(i.getId(), i.getAssignee());
                taskService.setAssignee(i.getId(), HIDDEN_ASSIGNEE_ID);
            });
        }
    }
}
