package cn.axzo.workflow.server.controller.listener.task;

import cn.axzo.workflow.common.enums.AutoApprovalTypeEnum;
import cn.axzo.workflow.common.model.request.BpmnApproveConf;
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.common.context.TaskOperationContext;
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler;
import cn.axzo.workflow.core.engine.tx.listener.AutoPassTransactionListener;
import cn.axzo.workflow.core.engine.tx.listener.AutoRejectTransactionListener;
import cn.axzo.workflow.core.listener.AbstractBpmnEventListener;
import cn.axzo.workflow.core.listener.BpmnTaskEventListener;
import cn.axzo.workflow.core.version.MultiVersionBeanUtils;
import cn.axzo.workflow.server.controller.listener.task.service.CheckApproverService;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.impl.cfg.TransactionState;
import org.flowable.common.engine.impl.context.Context;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.job.service.JobService;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.context.annotation.Scope;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Nullable;
import java.util.Objects;
import java.util.Optional;

import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;

/**
 * UserTask 节点自动通过和驳回处理
 *
 * @author wangli
 * @since 2023/11/21 11:30
 */
@Slf4j
@Component
@Scope("prototype")
@AllArgsConstructor
public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener<TaskOperationContext> implements BpmnTaskEventListener, Ordered {
    @Override
    public int getOrder() {
        return Integer.MIN_VALUE + 101;
    }

    private final RepositoryService repositoryService;

    @Override
    public void onCreated(DelegateTask delegateTask) {
        log.info("AutoOperatorEventListener#onCreated...{}, processInstanceId:{}", delegateTask.getTaskDefinitionKey(), delegateTask.getProcessInstanceId());

        if (Objects.equals(NODE_STARTER.getType(), delegateTask.getTaskDefinitionKey())) {
            createAsyncApproveJob(delegateTask);
            return;
        }

        Process mainProcess = repositoryService.getBpmnModel(delegateTask.getProcessDefinitionId()).getMainProcess();
        UserTask userTask = (UserTask) mainProcess.getFlowElement(delegateTask.getTaskDefinitionKey());

        Optional<BpmnApproveConf> processApproveConf = BpmnMetaParserHelper.getProcessApproveConf(mainProcess);
        // 开启了电子签名不能自动过审
        Boolean activitySignature = BpmnMetaParserHelper.getActivitySignature(mainProcess.getFlowElement(delegateTask.getTaskDefinitionKey()));
        //自动过审配置连续节点自动过审才处理，历史数据默认不自动过审
        if (processApproveConf.isPresent()
                && AutoApprovalTypeEnum.CONTINUOUS_NODES_AUTO_APPROVAL == processApproveConf.get().getAutoApprovalType()
                && !activitySignature) {
            Object versionVar = delegateTask.getVariable(WORKFLOW_ENGINE_VERSION);
            String version = versionVar == null ? null : String.valueOf(versionVar);
            CheckApproverService checkApproverService = MultiVersionBeanUtils.getSpecifiedVersionBean(CheckApproverService.class, version);
            boolean exists = checkApproverService.checkApproverExists(delegateTask, userTask, mainProcess, getContext());
            log.info("是否需要自动过程判断 exists:{},processInstId:{},taskDefinitionKey:{}", exists, delegateTask.getProcessInstanceId(), delegateTask.getTaskDefinitionKey());
            if (exists) {
                autoPass(delegateTask, null,"已同意（同一审批人，自动过审）");
            }
        }
        // 检测节点自身配置是否有自动操作
        checkApprovalMethod(delegateTask, userTask);

        log.info("AutoOperatorEventListener#onCreated...end:{}, processInstanceId:{}", delegateTask.getTaskDefinitionKey(), delegateTask.getProcessInstanceId());
    }

    private void createAsyncApproveJob(DelegateTask delegateTask) {
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
        JobService jobService = processEngineConfiguration.getJobServiceConfiguration().getJobService();

        JobEntity job = jobService.createJob();
        // 这里的 executionId 可为 null
        job.setExecutionId(delegateTask.getExecutionId());
        job.setProcessInstanceId(delegateTask.getProcessInstanceId());
        job.setProcessDefinitionId(delegateTask.getProcessDefinitionId());
        job.setElementId(delegateTask.getTaskDefinitionKey());
        job.setElementName(delegateTask.getName());
        job.setJobHandlerType(AsyncApproveTaskJobHandler.TYPE);
        job.setTenantId(delegateTask.getTenantId());

        BpmnTaskAuditDTO dto = new BpmnTaskAuditDTO();
        dto.setTaskId(delegateTask.getId());

        BpmnTaskDelegateAssigner initiator = getContext().getInitiator(() -> BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR)));
        if (Objects.nonNull(initiator)) {
            delegateTask.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + delegateTask.getId(),
                    initiator.toJson());
        }
        dto.setApprover(initiator);

        // 携带自定义的数据
        job.setCustomValues(JSONUtil.toJsonStr(dto));

        // 创建异步任务并调度
        jobService.createAsyncJob(job, false);
        jobService.scheduleAsyncJob(job);
    }

    /**
     * 如果审批人为空时, 读取 approverEmptyHandleType = 自动通过或自动驳回
     *
     * @param delegateTask
     * @param userTask
     */
    private void checkApproverEmptyHandle(DelegateTask delegateTask, UserTask userTask) {
        if (!StringUtils.hasText(delegateTask.getAssignee())) {
            BpmnMetaParserHelper.getApproverEmptyHandleType(userTask)
                    .ifPresent(approverEmptyHandleTypeEnum -> {
                        switch (approverEmptyHandleTypeEnum) {
                            case autoPassed:
                                autoPass(delegateTask, "", "未找到审批人，自动同意");
                                break;
                            case autoRejection:
                                autoReject(delegateTask, "未找到审批人，自动驳回");
                                break;
                            case autoSkipped:
                                // autoReject(delegateTask);
                                // 非产品需求, 暂时不实现, 这里的功能似乎可以用 taskService.deleteTask 来实现
                                break;
                            default:
                                break;
                        }
                    });
        }
    }

    /**
     * 如果 approverMethod = 自动通过或自动驳回时
     *
     * @param delegateTask
     * @param userTask
     */
    private void checkApprovalMethod(DelegateTask delegateTask, UserTask userTask) {
        BpmnMetaParserHelper.getApprovalMethod(userTask)
                .ifPresent(approvalMethodEnum -> {
                    switch (approvalMethodEnum) {
                        case autoPassed:
                            autoPass(delegateTask);
                            break;
                        case autoRejection:
                            autoReject(delegateTask);
                            break;
                        case bizSpecify:
                            break;
                        default:
                            checkApproverEmptyHandle(delegateTask, userTask);
                            break;
                    }
                });
    }

    /**
     * 注意：该方法的调用需要考虑到会签节点，动态增减审批人时，对判断是否离开当前节点条件表达式会有一定影响
     * <p>
     * 建议：优先考虑使用 {@link AutoRejectTransactionListener} 事务监听
     *
     * @param delegateTask 自动操作的任务
     */
    private void autoReject(DelegateTask delegateTask, @Nullable String operationDesc) {
        Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED,
                new AutoRejectTransactionListener(delegateTask, operationDesc));
    }

    private void autoReject(DelegateTask delegateTask) {
        autoReject(delegateTask,"无需审批人，自动驳回" );
    }

    /**
     * 注意：该方法的调用需要考虑到会签节点，动态增减审批人时，对判断是否离开当前节点条件表达式会有一定影响
     * <p>
     * 建议：优先考虑使用 {@link AutoPassTransactionListener} 事务监听
     *
     * @param delegateTask 自动操作的任务
     * @param advice       添加自动操作任务时的额外意见
     */
    private void autoPass(DelegateTask delegateTask, @Nullable String advice, @Nullable String operationDesc) {
        Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED,
                new AutoPassTransactionListener(delegateTask, advice, operationDesc));
    }

    /**
     * 自动通过
     *
     * @param delegateTask 自动操作的任务
     */
    private void autoPass(DelegateTask delegateTask) {
        autoPass(delegateTask, null, "无需审批人，自动同意");
    }

}
