package cn.novalon.manage.sys.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

/**
 * 异步配置类
 * 
 * 文件定义：配置异步线程池，用于审计日志等异步处理
 * 涉及业务：提供统一的异步处理能力
 * 算法：使用ThreadPoolTaskExecutor管理线程池
 * 
 * @author 张翔
 * @date 2026-04-01
 */
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    private static final Logger logger = LoggerFactory.getLogger(AsyncConfig.class);

    @Bean(name = "auditLogExecutor")
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("audit-log-");
        
        executor.setRejectedExecutionHandler((r, exec) -> {
            logger.warn("审计日志线程池已满，任务被拒绝，将降级为同步处理");
            if (!exec.isShutdown()) {
                r.run();
            }
        });
        
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        
        executor.initialize();
        
        logger.info("审计日志异步线程池初始化完成: corePoolSize={}, maxPoolSize={}, queueCapacity={}", 
                   executor.getCorePoolSize(), executor.getMaxPoolSize(), executor.getQueueCapacity());
        
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (throwable, method, params) -> {
            logger.error("异步任务执行异常 - 方法: {}, 参数: {}, 异常: {}", 
                        method.getName(), params, throwable.getMessage(), throwable);
        };
    }
}
