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

import cn.axzo.workflow.common.exception.WorkflowEngineException;
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 com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.identity.Authentication;
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.engine.impl.util.ProcessDefinitionUtil;
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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.axzo.workflow.common.code.OtherRespCode.ASSIGNEE_NODE_ID_NOT_EXISTS;
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_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
import static cn.axzo.workflow.common.constant.BpmnConstants.RESET_TASK_ASSIGNER_SHOW_NUMBER;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ASSIGNEE_SKIP_FLAT;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.UPGRADED;
import static cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner.buildDummyAssigner;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getCategoryVersion;
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 2025-06-24 17:17
 */
@Slf4j
public class CustomResetTaskApproversCmd extends AbstractCommand<Void> implements Serializable {

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

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

    @Override
    public String paramToJsonString() {
        Map<String, Object> params = new HashMap<>();
        params.put("originTaskId", originTaskId);
        params.put("advice", advice);
        params.put("attachmentList", JSON.toJSONString(attachmentList));
        params.put("originTaskAssignee", originTaskAssignee);
        params.put("targetTaskAssigneeList", JSON.toJSONString(targetTaskAssigneeList));
        return JSON.toJSONString(params);
    }

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

        TaskService taskService = processEngineConfiguration.getTaskService();
        TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(originTaskId).singleResult();
        validTargetAssigneeNodeId(task.getProcessDefinitionId());
        validTask(historicTaskInstance, task, originTaskAssignee, null);

        resolveOriginTask(commandContext, taskService, task);
        batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList,
                originTaskAssignee);
        resetActivityApprovers(commandContext, task, targetTaskAssigneeList, taskService);

        return null;
    }

    private void resetActivityApprovers(CommandContext commandContext, TaskEntity taskEntity, List<BpmnTaskDelegateAssigner> taskDelegateAssigners, TaskService taskService) {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();

        // 提前查询正在待审批的任务， 用于最后移除
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(taskEntity.getProcessInstanceId()).active().list();

        // 这个节点下所有审批人快照
        String activityListSnapshot =
                INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey();
        Map<String, Object> variables = new HashMap<>();
        variables.put(activityListSnapshot, taskDelegateAssigners);
        variables.put(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + taskEntity.getTaskDefinitionKey(), taskDelegateAssigners.stream().map(BpmnTaskDelegateAssigner::buildAssigneeId).collect(Collectors.toList()));
        runtimeService.setVariables(taskEntity.getProcessInstanceId(), variables);
        log.info("正在进行提级任务:{},提级审批人列表:{}", taskEntity.getId(), JSONUtil.toJsonStr(taskDelegateAssigners));

        // 将提级审批人加签
        taskDelegateAssigners.forEach(assigner -> CustomTaskHelper.addMultiTask(commandContext, taskEntity, assigner));

        taskEntity.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), UPGRADED.getStatus());

        CustomTaskHelper.deleteMultiTasks(commandContext, tasks);
        // 移除引擎内部用于确定人的快照变量
//        runtimeService.removeVariables(taskEntity.getProcessInstanceId(), variables.keySet());
    }

    private void resolveOriginTask(CommandContext commandContext, TaskService taskService, TaskEntity task) {
        BpmnTaskDelegateAssigner assigner = buildDummyAssigner("upgrade", TASK_ASSIGNEE_SKIP_FLAT, "dummyApprover");
        task.setAssignee(assigner.buildAssigneeId());
        task.setScopeType("UPGRADE");

        Authentication.setAuthenticatedUserId(originTaskAssignee.buildAssigneeId());

        // 构建评论内容
        StringBuilder message = new StringBuilder("提级给");
        int end = Math.min(targetTaskAssigneeList.size(), RESET_TASK_ASSIGNER_SHOW_NUMBER);
        //加签人员数量显示指定个数
        for (int i = 0; i < end; i++) {
            message.append(targetTaskAssigneeList.get(i).getAssignerName());
            if (i < end - 1) {
                message.append("、");
            }
        }
        if (targetTaskAssigneeList.size() > end) {
            message.append("等")
                    .append(targetTaskAssigneeList.size())
                    .append("人");
        }
        message.append("审批");
        addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, message.toString());
        addComment(commandContext, task, COMMENT_TYPE_ADVICE, advice);
        Authentication.setAuthenticatedUserId(null);

        taskService.saveTask(task);
    }

    private void validTargetAssigneeNodeId(String processDefinitionId) {
        BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);
        boolean present = targetTaskAssigneeList.stream().anyMatch(assigner -> !org.springframework.util.StringUtils.hasText(assigner.getNodeId()));
        Integer categoryVersion = getCategoryVersion(bpmnModel.getMainProcess()).orElse(0);
        if (categoryVersion > 0 && present) {
            throw new WorkflowEngineException(ASSIGNEE_NODE_ID_NOT_EXISTS, "审批人");
        }
    }
}
