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

import cn.axzo.workflow.core.engine.event.ExtTaskInstCreateEvent;
import cn.axzo.workflow.core.engine.event.ExtTaskInstEvent;
import cn.axzo.workflow.core.engine.event.ExtTaskInstUpdateEvent;
import cn.axzo.workflow.core.engine.event.ReceiveTaskEventType;
import cn.axzo.workflow.core.engine.job.AsyncExtTaskInstJobHandler;
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.ImmutableSet;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.AbstractFlowableEventListener;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
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.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Set;

import static cn.axzo.workflow.core.engine.event.ReceiveTaskEventType.CREATE;
import static cn.axzo.workflow.core.engine.event.ReceiveTaskEventType.UPDATE;

/**
 * 操作 ext_ax_taskinst 表的事件
 * <p>
 * 目前,该事件的两种状态,仅用在 BpmnTaskEventListener 的 onCreated 和 onDeleted 钩子函数上;
 * 和自定义的特殊用途的 Behavior 上.
 *
 * @author wangli
 * @since 2024/2/5 18:39
 */
@AllArgsConstructor
@Component
@Slf4j
public class ExtTaskInstEventListener extends AbstractFlowableEventListener {
    private final ExtAxHiTaskInstService extAxHiTaskInstService;
    public static final Set<ReceiveTaskEventType> SUPPORT_EVENTS =
            ImmutableSet.<ReceiveTaskEventType>builder()
                    .add(CREATE)
                    .add(UPDATE)
                    .build();

    /**
     * 不要将该类的方法异步化, 否则有一连串的坑
     *
     * @param flowableEvent
     */
    @Override
    public void onEvent(FlowableEvent flowableEvent) {
        if (flowableEvent instanceof ExtTaskInstEvent) {
            log.info("Ext Task Inst Event : {}, eventType: {}", JSONUtil.toJsonStr(flowableEvent), flowableEvent.getType());
            ExtTaskInstEvent event = (ExtTaskInstEvent) flowableEvent;
            ReceiveTaskEventType eventType = (ReceiveTaskEventType) flowableEvent.getType();
            if (SUPPORT_EVENTS.contains(eventType)) {
                switch (eventType) {
                    case CREATE:
                        saveExtTaskInst((ExtTaskInstCreateEvent) event);
                        break;
                    case UPDATE:
                        updateExtTaskInst((ExtTaskInstUpdateEvent) event);
                        break;
                    default:
                }
            }
        }
    }

    @Override
    public boolean isFailOnException() {
        return true;
    }

    private void saveExtTaskInst(ExtTaskInstCreateEvent event) {
        ExtAxHiTaskInst entity = new ExtAxHiTaskInst();
        entity.setProcInstId(event.getProcessInstanceId());
        entity.setTaskDefinitionKey(event.getActivityId());
        entity.setTaskId(event.getTaskId());
        if (StringUtils.hasText(event.getAssignee())) {
            entity.setAssignee(event.getAssignee());
        }
        entity.setStatus(event.getResultEnum().getStatus());
        extAxHiTaskInstService.save(entity);
    }

    private void updateExtTaskInst(ExtTaskInstUpdateEvent event) {
//        extAxHiTaskInstService.updateByTaskIdAndInstanceId(event.getTaskId(), event.getProcessInstanceId(),
//                event.getAssignee(), event.getResultEnum());
        // 利用引擎异步任务的重试能力, 去正确更新扩展任务表的状态
        createAsyncJob(event);
    }

    private void createAsyncJob(ExtTaskInstUpdateEvent event) {
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
        processEngineConfiguration.getCommandExecutor().execute(commandContext -> {
            JobService jobService = CommandContextUtil.getJobService(commandContext);
            JobEntity job = jobService.createJob();
            job.setJobHandlerType(AsyncExtTaskInstJobHandler.TYPE);

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

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

    /*private void externalJob(ExtTaskInstUpdateEvent event) {
        CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
        ManagementService managementService = processEngineConfiguration.getManagementService();
        commandExecutor.execute((Command<Void>) commandContext -> {
            JobService jobService = CommandContextUtil.getJobService(commandContext);
            JobServiceConfiguration jobServiceConfiguration = processEngineConfiguration.getJobServiceConfiguration();
            ExternalWorkerJobEntity workerJob = jobService.createExternalWorkerJob();
            workerJob.setJobHandlerConfiguration("extHiTaskInst");
            workerJob.setJobType(Job.JOB_TYPE_EXTERNAL_WORKER);
            workerJob.setRetries(jobServiceConfiguration.getAsyncExecutorNumberOfRetries());
            workerJob.setJobHandlerType(AsyncExtTaskInstJobHandler.TYPE);
            workerJob.setProcessInstanceId(event.getProcessInstanceId());
            workerJob.setCustomValues(JSONUtil.toJsonStr(event));
            jobService.insertExternalWorkerJob(workerJob);
            return null;
        });

        List<AcquiredExternalWorkerJob> acquiredJobs = managementService.createExternalWorkerJobAcquireBuilder()
                .topic("extHiTaskInst", Duration.ofMinutes(30))
                .acquireAndLock(3, "testWorker");
        acquiredJobs.forEach(i -> {
            managementService.createExternalWorkerCompletionBuilder(i.getId(), "testWorker").complete();
        });
    }*/
}
