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

import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
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 java.io.Serializable;
import java.util.List;

import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN;
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.createVirtualTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;

/**
 * 自定义的加签用户任务命令实现
 * <p>
 * 支持向前/向后/共享三种加签的模式
 *
 * @author wangli
 * @since 2023/12/25 14:05
 */
@Slf4j
public class CustomCountersignUserTaskCmd implements Command<Void>, Serializable {

    private final BpmnCountersignTypeEnum countersignType;
    private final String originTaskId;
    private final BpmnTaskDelegateAssigner originTaskAssignee;
    private final String advice;
    private final List<AttachmentDTO> attachmentList;
    private final List<BpmnTaskDelegateAssigner> targetTaskAssigneeList;
    private final ExtAxHiTaskInstService extAxHiTaskInstService;

    public CustomCountersignUserTaskCmd(BpmnCountersignTypeEnum countersignType, String originTaskId,
                                        BpmnTaskDelegateAssigner originTaskAssignee, String advice,
                                        List<AttachmentDTO> attachmentList,
                                        List<BpmnTaskDelegateAssigner> targetTaskAssigneeList, ExtAxHiTaskInstService extAxHiTaskInstService) {
        this.countersignType = countersignType;
        this.originTaskId = originTaskId;
        this.originTaskAssignee = originTaskAssignee;
        this.advice = advice;
        this.attachmentList = attachmentList;
        this.targetTaskAssigneeList = targetTaskAssigneeList;
        this.extAxHiTaskInstService = extAxHiTaskInstService;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        HistoricTaskInstanceQuery taskQuery =
                processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
        HistoricTaskInstance historicTaskInstance = taskQuery.taskId(originTaskId).singleResult();

        TaskService taskService = processEngineConfiguration.getTaskService();
        Task task = taskService.createTaskQuery().taskId(originTaskId).singleResult();

        validTask(historicTaskInstance, (TaskEntity) task, originTaskAssignee);

        List<BpmnTaskDelegateAssigner> taskDelegateAssigners =
                validTaskAssignerDuplicated(commandContext, (TaskEntity) task, targetTaskAssigneeList);

        resolveOriginTask(commandContext, extAxHiTaskInstService, taskService, task);

        batchAddAttachment(commandContext, task.getProcessInstanceId(), task.getId(), attachmentList,
                originTaskAssignee);

        switch (countersignType) {
            case FORWARD_COUNTERSIGN:
                // TODO
                break;
            case BACK_COUNTERSIGN:
                // TODO
                break;
            default:
                // share_counterSign
                shareCountSign(commandContext, (TaskEntity) task, taskDelegateAssigners);
                break;
        }

        return null;
    }

    /**
     * 共享签
     *
     * @param commandContext
     * @param taskEntity
     * @param taskDelegateAssigners 当前任务的原审批人列表
     */
    private void shareCountSign(CommandContext commandContext, TaskEntity taskEntity,
                                List<BpmnTaskDelegateAssigner> taskDelegateAssigners) {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
        // 这个节点下所有审批人快照
        String activityListSnapshot =
                INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey();
        taskDelegateAssigners.addAll(targetTaskAssigneeList);
        runtimeService.setVariable(taskEntity.getProcessInstanceId(), activityListSnapshot, taskDelegateAssigners);
        log.info("正在进行加签任务:{},待加签人合并列表:{}", taskEntity.getId(), JSONUtil.toJsonStr(taskDelegateAssigners));

        targetTaskAssigneeList.forEach(assigner -> {
            CustomTaskHelper.addMultiTask(commandContext, taskEntity, assigner);
        });
    }

    private void resolveOriginTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService,
                                   TaskService taskService, Task task) {
        // 构建评论内容
        StringBuilder message = new StringBuilder("添加");
        for (int i = 0; i < targetTaskAssigneeList.size(); i++) {
            message.append(targetTaskAssigneeList.get(i).getAssignerName());
            if (i < targetTaskAssigneeList.size() - 1) {
                message.append("、");
            }
        }
        message.append("等").append(targetTaskAssigneeList.size()).append("人进行审批");
        Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(),
                task.getTaskDefinitionKey(), advice, originTaskAssignee, COUNTERSIGN.getStatus());
        addComment(commandContext, virtualTask, COMMENT_TYPE_OPERATION_DESC, message.toString());
        batchAddAttachment(commandContext, task.getProcessInstanceId(), task.getId(), attachmentList, originTaskAssignee);
    }
}
