package com.easyagents.flow.core.test;

import com.easyagents.flow.core.chain.Chain;
import com.easyagents.flow.core.chain.ChainDefinition;
import com.easyagents.flow.core.chain.repository.InMemoryChainStateRepository;
import com.easyagents.flow.core.util.JsConditionUtil;
import org.junit.Assert;
import org.junit.Test;

import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * GraalVM 条件表达式编译复用与上下文隔离回归测试。
 */
public class JsConditionUtilTest {

    /**
     * 验证相同 Source 在不同 Context 中不会残留上一次变量。
     */
    @Test
    public void shouldIsolateVariablesWhenReusingSource() {
        Chain chain = chain("js-isolation");

        Assert.assertTrue(JsConditionUtil.eval(
                "value > 10", chain, Map.of("value", 11)));
        Assert.assertFalse(JsConditionUtil.eval(
                "value > 10", chain, Map.of("value", 9)));
    }

    /**
     * 验证共享 Engine 和 Source 可被多个隔离 Context 并发使用。
     *
     * @throws Exception 等待并发任务被中断时抛出
     */
    @Test
    public void shouldEvaluateSharedSourceConcurrently()
            throws Exception {
        Chain chain = chain("js-concurrent");
        ExecutorService workers =
                Executors.newFixedThreadPool(4);
        CountDownLatch completed =
                new CountDownLatch(20);
        AtomicInteger failures =
                new AtomicInteger();
        try {
            for (int value = 0; value < 20; value++) {
                int current = value;
                workers.submit(() -> {
                    try {
                        boolean result = JsConditionUtil.eval(
                                "value % 2 === 0",
                                chain,
                                Map.of("value", current));
                        if (result != (current % 2 == 0)) {
                            failures.incrementAndGet();
                        }
                    } catch (Throwable error) {
                        failures.incrementAndGet();
                    } finally {
                        completed.countDown();
                    }
                });
            }
            Assert.assertTrue(completed.await(
                    10L, TimeUnit.SECONDS));
            Assert.assertEquals(0, failures.get());
        } finally {
            workers.shutdownNow();
        }
    }

    /**
     * 创建带初始化状态的工作流。
     *
     * @param instanceId 实例 ID
     * @return 测试工作流
     */
    private Chain chain(String instanceId) {
        Chain chain = new Chain(
                new ChainDefinition(), instanceId);
        chain.setChainStateRepository(
                new InMemoryChainStateRepository());
        chain.initializeState();
        return chain;
    }
}
