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

import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
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.RuntimeService;
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.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

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

import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER;
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.core.engine.cmd.helper.CustomTaskHelper.addComment;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;

/**
 * 自定义(同步)审批通过任务的命令器实现
 *
 * @author wangli
 * @since 2024/1/4 15:50
 */
public class CustomApproveTaskCmd implements Command<Void>, Serializable {

    private static final Logger log = LoggerFactory.getLogger(CustomApproveTaskCmd.class);
    private final String taskId;
    private final String advice;
    /**
     * 不传,默认"已通过"
     */
    private String operationDesc = "已通过";
    /**
     * 附件, 可为空
     */
    private final List<AttachmentDTO> attachmentList;
    private final BpmnTaskDelegateAssigner approver;
    /**
     * 下级节点的审批,可为空
     */
    private final BpmnTaskDelegateAssigner nextApprover;

    public CustomApproveTaskCmd(BpmnTaskAuditDTO dto) {
        this.taskId = dto.getTaskId();
        this.advice = dto.getAdvice();
        this.attachmentList = dto.getAttachmentList();
        this.approver = dto.getApprover();
        this.nextApprover = dto.getNextApprover();
    }

    public CustomApproveTaskCmd(String taskId, String advice, String operationDesc, List<AttachmentDTO> attachmentList,
                                BpmnTaskDelegateAssigner approver, BpmnTaskDelegateAssigner nextApprover) {
        this.taskId = taskId;
        this.advice = advice;
        this.operationDesc = operationDesc;
        this.attachmentList = attachmentList;
        this.approver = approver;
        this.nextApprover = nextApprover;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        HistoricTaskInstanceQuery taskQuery =
                processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
        TaskService taskService = processEngineConfiguration.getTaskService();

        HistoricTaskInstance historicTaskInstance = taskQuery.taskId(taskId).singleResult();

        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        validTask(historicTaskInstance, (TaskEntity) task, approver);

        if (StringUtils.hasLength(advice)) {
            Authentication.setAuthenticatedUserId(approver.buildAssigneeId());
            addComment(commandContext, task, COMMENT_TYPE_ADVICE, advice);
            Authentication.setAuthenticatedUserId(null);
        }

        batchAddAttachment(commandContext, task.getProcessInstanceId(), taskId, attachmentList, approver);

        Authentication.setAuthenticatedUserId(Objects.nonNull(approver) ? approver.buildAssigneeId() : null);
        addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc);
        Authentication.setAuthenticatedUserId(null);

        RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
        if (Objects.nonNull(nextApprover)) {
            // 主动设置下级审批人
            runtimeService.setVariable(task.getProcessInstanceId(), INTERNAL_SPECIFY_NEXT_APPROVER,
                    nextApprover);
        }
        ((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus());

        executeSynchronous(task, taskService, runtimeService);
        return null;
    }

    private void executeSynchronous(Task task, TaskService taskService, RuntimeService runtimeService) {
        if (StringUtils.hasText(task.getExecutionId())) {
            // 正常完成流程任务，审批通过
            taskService.complete(task.getId(), runtimeService.getVariables(task.getExecutionId()));
        } else {
            // 特殊的完成单独创建的任务
            taskService.complete(task.getId());
        }
    }

}
