package cn.axzo.workflow.core.listener.impl;

import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
import cn.axzo.workflow.common.model.dto.TermNodeAddTimerJobDTO;
import cn.axzo.workflow.common.model.dto.TermNodePausingDTO;
import cn.axzo.workflow.core.common.context.ActivityOperationContext;
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
import cn.axzo.workflow.core.engine.tx.listener.AddTimerJobTransactionListener;
import cn.axzo.workflow.core.listener.AbstractBpmnEventListener;
import cn.axzo.workflow.core.listener.BpmnActivityEventListener;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.common.engine.impl.cfg.TransactionState;
import org.flowable.common.engine.impl.context.Context;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.springframework.context.annotation.Scope;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.util.Objects;

import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_NODE_ALTER;

/**
 * Core 包内置的活动事件处理,可共用与 Jar 包集成和微服务集成
 * <p>
 * 该监听主要是监听启动“无人”的业务节点超时告警功能
 *
 * @author wangli
 * @since 2024-09-11 11:44
 */
@Slf4j
@Component
@Scope("prototype")
@AllArgsConstructor
public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnEventListener<ActivityOperationContext> implements BpmnActivityEventListener, Ordered {
    private final SupportRefreshProperties refreshProperties;

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE;
    }

    /**
     * 节点已启动
     * <p>
     * 创建一个周期性监控业务节点执行状态的任务
     *
     * @param execution
     */
    @Override
    public void onStart(DelegateExecution execution) {
        if (!Boolean.TRUE.equals(refreshProperties.getAlterEnable())) {
            return;
        }
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
        RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
        TermNodePausingDTO dto = new TermNodePausingDTO(execution.getProcessInstanceId(), execution.getCurrentActivityId(), 0);
        runtimeService.setVariable(execution.getProcessInstanceId(), BIZ_NODE_ALTER + execution.getCurrentActivityId(), dto);
        BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(execution.getProcessDefinitionId());
        FlowElement flowElement = bpmnModel.getFlowElement(execution.getCurrentActivityId());
        BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(e -> {
            if (Objects.equals(BpmnFlowNodeType.NODE_BUSINESS, e)) {
                BpmnMetaParserHelper.getApprovalMethod(flowElement).ifPresent(method -> {
                    switch (method) {
                        case nobody:
                        case bizSpecify:
                            // 业务指定审批人，需要在业务设置了人后，设置定时
                            String timeUnit;
                            switch (refreshProperties.getAlterIntervalUnit()) {
                                case MINUTES:
                                    timeUnit = "M";
                                    break;
                                case HOURS:
                                    timeUnit = "H";
                                    break;
                                default:
                                    timeUnit = "S";
                                    break;

                            }

                            TermNodeAddTimerJobDTO addTimerJobDTO = new TermNodeAddTimerJobDTO();
                            addTimerJobDTO.setProcessInstanceId(execution.getProcessInstanceId());
                            addTimerJobDTO.setActivityId(execution.getCurrentActivityId());
                            addTimerJobDTO.setDelayTime(refreshProperties.getAlterInterval());
                            addTimerJobDTO.setTimeUnit(timeUnit);

                            Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED,
                                    new AddTimerJobTransactionListener(addTimerJobDTO));
                            break;
                        default:
                            break;
                    }
                });
            }
        });
    }

}
