package cn.axzo.workflow.core.conf;

import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory;
import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory;
import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator;
import cn.axzo.workflow.core.engine.job.AsyncAbortProcessInstanceHandler;
import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncBpmnProcessActivityJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncCancelProcessInstanceHandler;
import cn.axzo.workflow.core.engine.job.AsyncCountersignUserTaskJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncExtTaskInstJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncRejectTaskJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncTransferUserTaskJobHandler;
import cn.axzo.workflow.core.engine.job.exception.handle.CustomAsyncJobLogClearTraceExceptionHandler;
import cn.axzo.workflow.core.engine.job.exception.handle.CustomAsyncRunnableExceptionExceptionHandler;
import cn.axzo.workflow.core.engine.persistence.CustomMybatisHistoricProcessInstanceDataManager;
import cn.axzo.workflow.core.service.BpmnProcessActivityService;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.google.common.collect.Lists;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.common.engine.impl.history.HistoryLevel;
import org.flowable.form.spring.SpringFormEngineConfiguration;
import org.flowable.job.service.JobProcessor;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;
import java.util.List;

import static org.flowable.common.engine.impl.AbstractEngineConfiguration.DB_SCHEMA_UPDATE_TRUE;

/**
 * Flowable 引擎相关全局配置
 *
 * @author wangli
 * @since 2023/7/13 11:18
 */
@Configuration
public class FlowableConfiguration {

    @Value("${workflow.enableVerboseExecutionTreeLogging:false}")
    private Boolean enableVerboseExecutionTreeLogging;

    @Bean
    public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> processEngineConfigurer(
            ObjectProvider<FlowableEventListener> listeners,
            CustomActivityBehaviorFactory customActivityBehaviorFactory,
            ExtAxHiTaskInstService extAxHiTaskInstService,
            BpmnProcessActivityService bpmnProcessActivityService,
            List<JobProcessor> jobProcessors,
            NacosServiceManager nacosServiceManager,
            NacosDiscoveryProperties nacosDiscoveryProperties) {
        return configuration -> {
            configuration.setEnableHistoricTaskLogging(true);
            configuration.setHistoryLevel(HistoryLevel.AUDIT);
            configuration.setHistory(HistoryLevel.AUDIT.getKey());
            configuration.setJobProcessors(jobProcessors);
            configuration.setEventListeners(Lists.newArrayList(listeners));
            configuration.setActivityBehaviorFactory(customActivityBehaviorFactory);
            configuration.setDatabaseSchemaUpdate(DB_SCHEMA_UPDATE_TRUE);
            configuration.setEnableSafeBpmnXml(false);
            //            configuration.setCreateDiagramOnDeploy(false);
//            configuration.setIdGenerator(new TimeBasedIdGenerator());
//            configuration.setIdGenerator(new DistributedTimeBasedIdGenerator(stringRedisTemplate));
            configuration.setIdGenerator(new BasedNacosSnowflakeIdGenerator(nacosServiceManager, nacosDiscoveryProperties));
            configuration.setHistoricProcessInstanceDataManager(new CustomMybatisHistoricProcessInstanceDataManager(configuration));
            // 自定义的异步任务处理器
            configuration.addCustomJobHandler(new AsyncApproveTaskJobHandler());
            configuration.addCustomJobHandler(new AsyncRejectTaskJobHandler(extAxHiTaskInstService));
            configuration.addCustomJobHandler(new AsyncExtTaskInstJobHandler(extAxHiTaskInstService));
            configuration.addCustomJobHandler(new AsyncTransferUserTaskJobHandler());
            configuration.addCustomJobHandler(new AsyncCountersignUserTaskJobHandler(extAxHiTaskInstService));
            configuration.addCustomJobHandler(new AsyncCancelProcessInstanceHandler(extAxHiTaskInstService));
            configuration.addCustomJobHandler(new AsyncAbortProcessInstanceHandler(extAxHiTaskInstService));
            configuration.addCustomJobHandler(new AsyncBpmnProcessActivityJobHandler(bpmnProcessActivityService));
            // 异步任务异常重试时间间隔
            configuration.setDefaultFailedJobWaitTime(30);
            configuration.setAsyncFailedJobWaitTime(30);
            configuration.getAsyncExecutorConfiguration().setAsyncJobLockTime(Duration.ofMinutes(5));
            configuration.getAsyncExecutorConfiguration().setGlobalAcquireLockEnabled(true);
            configuration.setAddDefaultExceptionHandler(false);
            configuration.setEnableVerboseExecutionTreeLogging(enableVerboseExecutionTreeLogging);
            configuration.setCustomAsyncRunnableExecutionExceptionHandlers(Lists.newArrayList(
                    new CustomAsyncJobLogClearTraceExceptionHandler(),
                    new CustomAsyncRunnableExceptionExceptionHandler()));
            configuration.setCommandContextFactory(new CustomCommandContextFactory());
        };
    }

    @Bean
    public EngineConfigurationConfigurer<SpringFormEngineConfiguration> formEngineConfigurer() {
        return configuration -> configuration.setDatabaseSchemaUpdate(DB_SCHEMA_UPDATE_TRUE);
    }

    @Bean
    public CustomActivityBehaviorFactory customActivityBehaviorFactory() {
        return new CustomActivityBehaviorFactory();
    }

}
