package tech.easyflow.ai.easyagentsflow.config;

import com.easyagents.flow.core.chain.runtime.ChainExecutor;
import com.easyagents.flow.core.chain.runtime.TriggerScheduler;
import com.easyagents.flow.core.chain.runtime.TriggerStore;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 工作流持久化触发调度器配置。
 */
@Configuration
@EnableConfigurationProperties({
        WorkflowRuntimeProperties.class,
        WorkflowIoProperties.class
})
public class WorkflowTriggerSchedulerConfig {

    /**
     * 创建使用 Redis 触发器仓储的独立调度器。
     *
     * @param triggerStore 持久化触发器仓储
     * @param properties 调度运行时配置
     * @return 工作流触发调度器
     */
    @Bean(destroyMethod = "shutdown")
    public TriggerScheduler workflowTriggerScheduler(
            TriggerStore triggerStore, WorkflowRuntimeProperties properties) {
        int schedulerThreads = Math.max(1, properties.getSchedulerThreads());
        int workerCoreSize = Math.max(1, properties.getWorkerCoreSize());
        int workerMaxSize = Math.max(workerCoreSize, properties.getWorkerMaxSize());
        int queueCapacity = Math.max(1, properties.getWorkerQueueCapacity());
        Duration scanInterval = properties.getTriggerScanInterval();
        long scanIntervalMillis = scanInterval == null ? 5000L : Math.max(1000L, scanInterval.toMillis());

        ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(
                schedulerThreads, namedThreadFactory("workflow-trigger-scheduler"));
        scheduler.setRemoveOnCancelPolicy(true);
        ThreadPoolExecutor worker = new ThreadPoolExecutor(
                workerCoreSize,
                workerMaxSize,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(queueCapacity),
                namedThreadFactory("workflow-node-worker"),
                new ThreadPoolExecutor.AbortPolicy());
        TriggerScheduler triggerScheduler = new TriggerScheduler(
                triggerStore, scheduler, worker, scanIntervalMillis);
        int childLaneMaxDepth = Math.max(
                1, properties.getChildWorkflowLaneMaxDepth());
        int childLaneMaxThreads = Math.max(
                1, properties.getChildWorkflowLaneMaxThreads());
        /*
         * 不同嵌套深度使用独立小通道。depth N 的 WorkflowNode 即使全部同步等待，
         * depth N+1 的触发器仍有独立容量，不会形成同池递归饥饿。
         */
        for (int depth = 1; depth <= childLaneMaxDepth; depth++) {
            ThreadPoolExecutor childWorkflowWorker =
                    new ThreadPoolExecutor(
                            0,
                            childLaneMaxThreads,
                            60L,
                            TimeUnit.SECONDS,
                            new SynchronousQueue<>(),
                            namedThreadFactory(
                                    "workflow-child-" + depth),
                            new ThreadPoolExecutor.AbortPolicy());
            childWorkflowWorker.allowCoreThreadTimeOut(true);
            triggerScheduler.registerWorker(
                    ChainExecutor.childExecutionLane(depth),
                    childWorkflowWorker);
        }
        return triggerScheduler;
    }

    /**
     * 创建带稳定前缀的守护线程工厂。
     *
     * @param prefix 线程名前缀
     * @return 线程工厂
     */
    private ThreadFactory namedThreadFactory(String prefix) {
        AtomicInteger sequence = new AtomicInteger();
        return task -> {
            Thread thread = new Thread(task, prefix + "-" + sequence.incrementAndGet());
            thread.setDaemon(true);
            return thread;
        };
    }
}
