package cn.axzo.workflow.core.engine.tx.listener;

import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskAsyncCmd;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.cfg.TransactionListener;
import org.flowable.common.engine.impl.interceptor.CommandConfig;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
import org.flowable.engine.RuntimeService;
import org.flowable.job.service.JobServiceConfiguration;
import org.flowable.job.service.impl.asyncexecutor.ResetExpiredJobsCmd;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.task.service.delegate.DelegateTask;

import java.util.Collections;

import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
import static org.flowable.common.engine.impl.interceptor.EngineConfigurationConstants.KEY_PROCESS_ENGINE_CONFIG;

/**
 * 自动过审的事务监听器
 * <p>
 * 在节点会签模式下，业务指定审批人、加签时，由于这两个动作的内部是先进行 addMultiTask ,对当前节点加了新的实例数，
 * 而该动作默认会触发多种内外部实现的监听，其中一个监听是自动过审，此时，节点的完成条件 nrOfInstance == nrOfCompleteInstances 一定不满足，
 * 所以无法跳出当前节点。当 addMultiTask 执行完后，便会再执行 deleteMultiTask，但该动作只是把 nrOfInstance == nrOfCompleteInstances
 * 表达式中的两个变量值变成了可以为 true 的结果。但并不会再触发节点的 leave 动作。
 *
 * <pre>
 * 使用示例:
 *  Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED, new AutoPassTransactionListener(delegateTask, ["advice"]));
 * </pre>
 *
 * @author wangli
 * @since 2024-08-07 10:24
 */
@Slf4j
@AllArgsConstructor
public class AutoPassTransactionListener implements TransactionListener {
    private final DelegateTask delegateTask;
    private final String advice;
    private final String operationDesc;

    @Override
    public void execute(CommandContext commandContext) {
        log.info("exec auto pass transaction listener start, processInstanceId: {}, taskId: {}", delegateTask.getProcessInstanceId(), delegateTask.getId());

        SpringProcessEngineConfiguration springProcessEngineConfiguration = (SpringProcessEngineConfiguration) commandContext
                .getEngineConfigurations().get(KEY_PROCESS_ENGINE_CONFIG);

        RuntimeService runtimeService = springProcessEngineConfiguration.getRuntimeService();
        BpmnTaskDelegateAssigner assigner = BpmnTaskDelegateAssigner.toObjectCompatible(
                runtimeService.getVariable(delegateTask.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_INFO + delegateTask.getId()));
        log.info("auto pass transaction listener, assigner: {}", JSON.toJSONString(assigner));
        CommandConfig commandConfig = new CommandConfig().transactionRequired();
        CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor();
        BpmnTaskAuditDTO pass = new BpmnTaskAuditDTO();
        pass.setTaskId(delegateTask.getId());
        pass.setAdvice(advice);
        pass.setApprover(assigner);
        pass.setOperationDesc(operationDesc);
        String jobId = commandExecutor.execute(commandConfig, new CustomApproveTaskAsyncCmd(pass));

        // 重置任务，因为上面的 cmd 和这个 cmd 的 lock 对象不一致
        JobServiceConfiguration jobServiceConfiguration = springProcessEngineConfiguration.getJobServiceConfiguration();
        commandExecutor.execute(commandConfig, new ResetExpiredJobsCmd(Collections.singletonList(jobId), jobServiceConfiguration.getJobEntityManager(), jobServiceConfiguration));

        log.info("exec auto pass transaction listener end");
    }

}
