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

import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.agenda.AbstractOperation;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.job.api.Job;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;

import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.PROCESS_CLOSING_TYPE;

/**
 * 通用的在 Command 内执行删除流程实例时的额外操作
 *
 * @author wangli
 * @since 2024/1/3 20:03
 */
@Slf4j
public class DeleteProcessInstanceOperation extends AbstractOperation {
    private final String processInstanceId;
    private final ExtAxHiTaskInstService extAxHiTaskInstService;
    private String customDeleteReason;
    private final BpmnProcessInstanceResultEnum closingType;

    public DeleteProcessInstanceOperation(CommandContext commandContext, String processInstanceId,
                                          ExtAxHiTaskInstService extAxHiTaskInstService,
                                          BpmnProcessInstanceResultEnum closingType) {
        super(commandContext, null);
        this.processInstanceId = processInstanceId;
        this.extAxHiTaskInstService = extAxHiTaskInstService;
        this.closingType = closingType;
    }

    public DeleteProcessInstanceOperation(CommandContext commandContext, String processInstanceId,
                                          ExtAxHiTaskInstService extAxHiTaskInstService,
                                          String customDeleteReason, BpmnProcessInstanceResultEnum closingType) {
        super(commandContext, null);
        this.processInstanceId = processInstanceId;
        this.extAxHiTaskInstService = extAxHiTaskInstService;
        this.customDeleteReason = customDeleteReason;
        this.closingType = closingType;
    }

    @Override
    public void run() {
        ProcessEngineConfigurationImpl processEngineConfiguration =
                CommandContextUtil.getProcessEngineConfiguration(commandContext);
        HistoryService historyService = processEngineConfiguration.getHistoryService();

        // 有一些节点是普通的 task,没有 ExecutionId,所以先主动去完成这些 node
        List<HistoricTaskInstance> historyTaskList =
                historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).unfinished().list();
        TaskService taskService = processEngineConfiguration.getTaskService();
        if (!CollectionUtils.isEmpty(historyTaskList)) {
            historyTaskList.stream().filter(i -> Objects.isNull(i.getExecutionId()))
                    .forEach(i -> {
                        taskService.setAssignee(i.getId(), HIDDEN_ASSIGNEE_ID);
                        taskService.complete(i.getId());
                        extAxHiTaskInstService.deleteStatusByTaskId(i.getId(), processInstanceId);
                    });

        }

        ManagementService managementService = processEngineConfiguration.getManagementService();
        List<Job> timerJobs = managementService.createTimerJobQuery().processInstanceId(processInstanceId).list();
        if (!CollectionUtils.isEmpty(timerJobs)) {
            log.warn("timerjobs size: {}, processInstanceId: {}", timerJobs.size(), processInstanceId);
            timerJobs.forEach(e -> managementService.deleteTimerJob(e.getId()));
        }

        RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
        runtimeService.setVariableLocal(processInstanceId, PROCESS_CLOSING_TYPE, closingType);
        runtimeService.deleteProcessInstance(processInstanceId, StringUtils.hasText(customDeleteReason) ? customDeleteReason : HIDDEN_ASSIGNEE_ID);
        // 将结束流程实例的原因记录下来
//        runtimeService.deleteProcessInstance(processInstanceId, reason);


    }
}
