package com.base.orbit.thread;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;

/**
 * {@link ThreadPoolTaskExecutor} 快捷构造类
 *
 * @author jhzhu
 * @date 2022-01-27
 */
@Slf4j
public class ThreadPoolTaskExecutorBuilder {

    private String executorName;
    private Integer corePoolSize;
    private Integer queueCapacity;
    private Integer maxPoolSize;
    private Integer keepAliveSeconds;
    private boolean allowCoreThreadTimeOut;
    private String threadNamePrefix;
    private String threadGroupName;
    private ThreadFactory threadFactory;
    private RejectedExecutionHandler rejectedExecutionHandler;
    private List<TaskDecorator> taskDecorators = new ArrayList<>();

    private ThreadPoolTaskExecutorBuilder() {

    }

    public static ThreadPoolTaskExecutorBuilder create() {
        return new ThreadPoolTaskExecutorBuilder();
    }

    public ThreadPoolTaskExecutorBuilder executorName(String executorName) {
        this.executorName = executorName;
        return this;
    }

    public ThreadPoolTaskExecutorBuilder corePoolSize(Integer corePoolSize) {
        this.corePoolSize = corePoolSize;
        return this;
    }

    public ThreadPoolTaskExecutorBuilder queueCapacity(Integer queueCapacity) {
        this.queueCapacity = queueCapacity;
        return this;
    }

    public ThreadPoolTaskExecutorBuilder maxPoolSize(Integer maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
        return this;
    }

    public ThreadPoolTaskExecutorBuilder keepAliveSeconds(Integer keepAliveSeconds) {
        this.keepAliveSeconds = keepAliveSeconds;
        return this;
    }

    public ThreadPoolTaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
        this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
        return this;
    }

    public ThreadPoolTaskExecutorBuilder threadNamePrefix(String threadNamePrefix) {
        this.threadNamePrefix = threadNamePrefix;
        return this;
    }

    public ThreadPoolTaskExecutorBuilder threadGroupName(String threadGroupName) {
        this.threadGroupName = threadGroupName;
        return this;
    }

    public ThreadPoolTaskExecutorBuilder rejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) {
        this.rejectedExecutionHandler = rejectedExecutionHandler;
        return this;
    }

    public ThreadPoolTaskExecutorBuilder taskDecorator(TaskDecorator taskDecorator) {
        this.taskDecorators.add(taskDecorator);
        return this;
    }

    public ThreadPoolTaskExecutorBuilder taskDecorators(List<TaskDecorator> taskDecorators) {
        this.taskDecorators.addAll(taskDecorators);
        return this;
    }

    public ThreadPoolTaskExecutorBuilder threadFactory(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
        return this;
    }

    public ThreadPoolTaskExecutor build() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        if (!StringUtils.isEmpty(this.executorName)) {
            throw new IllegalArgumentException("请指定一个有业务含义的线程池名称!");
        } else {
            threadPoolTaskExecutor.setBeanName(this.executorName);
        }

        if (ObjectUtils.anyNull(this.corePoolSize, this.maxPoolSize, this.queueCapacity)) {
            throw new IllegalArgumentException("缺少必填参数:corePoolSize、maxPoolSize 和 queueCapacity");
        }
        threadPoolTaskExecutor.setCorePoolSize(this.corePoolSize);
        threadPoolTaskExecutor.setMaxPoolSize(this.maxPoolSize);
        threadPoolTaskExecutor.setQueueCapacity(this.queueCapacity);

        if (Objects.nonNull(this.keepAliveSeconds)) {
            threadPoolTaskExecutor.setKeepAliveSeconds(this.keepAliveSeconds);
        }
        threadPoolTaskExecutor.setAllowCoreThreadTimeOut(this.allowCoreThreadTimeOut);

        if (!StringUtils.isEmpty(this.threadNamePrefix)) {
            threadPoolTaskExecutor.setThreadNamePrefix(this.threadNamePrefix);
        }

        if (!StringUtils.isEmpty(this.threadGroupName)) {
            threadPoolTaskExecutor.setThreadGroupName(this.threadGroupName);
        }
        threadPoolTaskExecutor.setRejectedExecutionHandler(this.rejectedExecutionHandler);

        if (!CollectionUtils.isEmpty(this.taskDecorators)) {
            threadPoolTaskExecutor.setTaskDecorator(new CompositeTaskDecorator(this.taskDecorators));
        }

        threadPoolTaskExecutor.setThreadFactory(this.threadFactory);
        threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        threadPoolTaskExecutor.setAwaitTerminationSeconds(10);
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }
}
