package common.jfinal;

import com.jfinal.config.*;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.server.undertow.UndertowServer;
import com.jfinal.template.Engine;
import common.handler.AllCorsHandler;
import common.interceptor.role.RoleInterceptor;
import common.interceptor.ExceptionInterceptor;
import common.interceptor.empty.EmptyInterceptor;
import common.model._MappingKit;
import modules.address.AddressController;
import modules.deposit.DepositController;
import modules.hello.HelloController;
import modules.news.NewsController;
import modules.nftt.NfttController;
import modules.nftt.NfttStatusMaintenanceTask;
import modules.order.OrderController;
import modules.order.OrderService;
import modules.order.OrderStatusMaintenanceTask;
import modules.upload.UploadController;
import modules.user.UserController;
import modules.user.UserService;
import modules.withdraw.WithdrawController;
import modules.withdraw.WithdrawMaintenanceTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AppConfig extends JFinalConfig {
    public static final Logger LOGGER = LoggerFactory.getLogger(AppConfig.class);

    static String DB_URL = System.getenv("DB_URL");
    static String DB_USER = System.getenv("DB_USER");
    static String DB_PASSWORD = System.getenv("DB_PASSWORD");
    static String DEV_MODE = System.getenv("DEV_MODE");

    public static void main(String[] args) {
        UndertowServer.start(AppConfig.class, 8888, true);
    }

    public static DruidPlugin getDruidPlugin() {
        return new DruidPlugin(DB_URL, DB_USER, DB_PASSWORD);
    }

    @Override
    public void configConstant(Constants constants) {
        constants.setMaxPostSize(1024 * 1024 * 10);
        
        constants.setDevMode(DEV_MODE.equals("1"));
        constants.setInjectDependency(true);
    }

    @Override
    public void configRoute(Routes routes) {
        routes.add("/", HelloController.class);
        
        routes.add("/user", UserController.class);
        routes.add("/upload", UploadController.class);
        routes.add("/nftt", NfttController.class);
        routes.add("/order", OrderController.class);
        routes.add("/news", NewsController.class);
        routes.add("/withdraw", WithdrawController.class);
        routes.add("/deposit", DepositController.class);
        routes.add("/address", AddressController.class);
    }

    @Override
    public void configEngine(Engine engine) {

    }

    @Override
    public void configPlugin(Plugins plugins) {
        DruidPlugin dp = getDruidPlugin();
        plugins.add(dp);

        ActiveRecordPlugin arp = new ActiveRecordPlugin(dp);
        // 是否打印SQL
        // arp.setShowSql(DEV_MODE.equals("1"));
        // arp.setShowSql(true);
        arp.setShowSql(false);
        // 加载sql模板
        arp.addSqlTemplate("/common/all.sqlt");
        // 映射实体
        _MappingKit.mapping(arp);
        plugins.add(arp);

        // 初始化异步任务线程池
        // 核心线程数：根据CPU核数和任务类型调整
        // 最大线程数：通常是核心线程数的2倍，防止任务堆积
        // 队列容量：根据任务队列积压情况调整
        int corePoolSize = Runtime.getRuntime().availableProcessors();
        int maxPoolSize = corePoolSize * 2;
        int queueCapacity = 1000; // 适当大的队列，防止任务丢失

        // 或 AbortPolicy, DiscardPolicy
        // 全局线程池
        ExecutorService asyncTaskExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(queueCapacity),
                new ThreadPoolExecutor.CallerRunsPolicy() // 或 AbortPolicy, DiscardPolicy
        );
        LOGGER.info("异步任务线程池初始化成功，核心线程数: {}, 最大线程数: {}, 队列容量: {}", corePoolSize, maxPoolSize, queueCapacity);
        // 可以将 ExecutorService 实例保存到某个单例类或 JFinal 的共享属性中，方便在其他地方访问
        // me.set("asyncTaskExecutor", asyncTaskExecutor); // 不推荐直接用put，使用自己的全局Manager
        // 更好的方式是创建一个单例的 TaskScheduler
        TaskScheduler.init(asyncTaskExecutor);
        
        // 数据维护线程
        if (DEV_MODE.equals("0")) {
            TaskScheduler.submit(new OrderStatusMaintenanceTask(new OrderService(), new UserService()));
            TaskScheduler.submit(new NfttStatusMaintenanceTask());
            TaskScheduler.submit(new WithdrawMaintenanceTask());
        }
    }

    @Override
    public void configInterceptor(Interceptors interceptors) {
        // 配置全局异常拦截器
        interceptors.addGlobalActionInterceptor(new ExceptionInterceptor());
        // 配置全局参数拦截校验器
        interceptors.addGlobalActionInterceptor(new EmptyInterceptor());
        // 配置全局权限校验拦截器
        interceptors.addGlobalActionInterceptor(new RoleInterceptor());
    }

    @Override
    public void configHandler(Handlers handlers) {
        handlers.add(new AllCorsHandler());
    }

    // TaskScheduler.java (建议创建的全局单例类，用于管理线程池)
    public static class TaskScheduler {
        private static ExecutorService executor;

        // 私有构造器防止外部实例化
        private TaskScheduler() {}

        public static void init(ExecutorService executorService) {
            if (executor != null) {
                LOGGER.warn("TaskScheduler 已经初始化过，请勿重复初始化。");
                return;
            }
            executor = executorService;
        }

        public static void submit(Runnable task) {
            if (executor == null || executor.isShutdown()) {
                LOGGER.error("TaskScheduler 未初始化或已关闭，无法提交任务！");
                return;
            }
            executor.submit(task);
        }

        // 如果需要返回结果，使用 Callable
        // public static <T> Future<T> submit(Callable<T> task) { ... }
    }
}
