package tech.easyflow.agent.runtime;

import com.easyagents.agent.runtime.model.AgentGenerationOptions;
import com.easyagents.agent.runtime.model.AgentHttpVersionPolicy;
import com.easyagents.agent.runtime.model.AgentModelSpec;
import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.agent.entity.Agent;
import tech.easyflow.ai.entity.Model;
import tech.easyflow.ai.service.ModelService;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.Map;

/**
 * Agent 模型生成和 HTTP 传输配置编译测试。
 */
public class AgentRuntimeCompilerModelConfigTest {

    /**
     * 验证缺少 stream 时默认开启，显式关闭时保持关闭。
     *
     * @throws Exception 反射调用失败时抛出
     */
    @Test
    public void generationStreamShouldDefaultToTrueAndAllowFalse() throws Exception {
        AgentRuntimeCompiler compiler = new AgentRuntimeCompiler();

        AgentGenerationOptions defaultOptions = invokeGenerationOptions(compiler, Map.of());
        AgentGenerationOptions disabledOptions = invokeGenerationOptions(compiler, Map.of("stream", false));

        Assert.assertTrue(defaultOptions.getStream());
        Assert.assertFalse(disabledOptions.getStream());
    }

    /**
     * 验证模型 options 中的 HTTP 策略会编译到中立模型声明。
     *
     * @throws Exception 反射调用失败时抛出
     */
    @Test
    public void modelHttpPolicyShouldCompileFromOptions() throws Exception {
        Model model = model(Map.of("agentHttpVersionPolicy", "HTTP_1_1"));
        AgentRuntimeCompiler compiler = compiler(model);

        AgentModelSpec spec = invokeModelSpec(compiler);

        Assert.assertEquals(AgentHttpVersionPolicy.HTTP_1_1, spec.getHttpVersionPolicy());
    }

    /**
     * 验证未知 HTTP 策略安全回退到 AUTO。
     *
     * @throws Exception 反射调用失败时抛出
     */
    @Test
    public void unknownModelHttpPolicyShouldFallbackToAuto() throws Exception {
        Model model = model(Map.of("agentHttpVersionPolicy", "HTTP_3"));
        AgentRuntimeCompiler compiler = compiler(model);

        AgentModelSpec spec = invokeModelSpec(compiler);

        Assert.assertEquals(AgentHttpVersionPolicy.AUTO, spec.getHttpVersionPolicy());
    }

    /**
     * 创建已注入模型服务的编译器。
     *
     * @param model 模型
     * @return 编译器
     * @throws Exception 注入失败时抛出
     */
    private AgentRuntimeCompiler compiler(Model model) throws Exception {
        AgentRuntimeCompiler compiler = new AgentRuntimeCompiler();
        ModelService modelService = (ModelService) java.lang.reflect.Proxy.newProxyInstance(
                ModelService.class.getClassLoader(),
                new Class<?>[]{ModelService.class},
                (proxy, method, args) -> "getModelInstance".equals(method.getName()) ? model : null);
        Field field = AgentRuntimeCompiler.class.getDeclaredField("modelService");
        field.setAccessible(true);
        field.set(compiler, modelService);
        return compiler;
    }

    /**
     * 创建测试模型。
     *
     * @param options 模型扩展配置
     * @return 测试模型
     */
    private Model model(Map<String, Object> options) {
        Model model = new Model();
        model.setId(BigInteger.TEN);
        model.setModelName("test-model");
        model.setOptions(options);
        return model;
    }

    /**
     * 调用私有生成参数编译方法。
     *
     * @param compiler 编译器
     * @param config 生成配置
     * @return 生成参数
     * @throws Exception 反射调用失败时抛出
     */
    private AgentGenerationOptions invokeGenerationOptions(AgentRuntimeCompiler compiler,
                                                           Map<String, Object> config) throws Exception {
        Method method = AgentRuntimeCompiler.class.getDeclaredMethod("buildGenerationOptions", Map.class);
        method.setAccessible(true);
        return (AgentGenerationOptions) method.invoke(compiler, config);
    }

    /**
     * 调用私有模型声明编译方法。
     *
     * @param compiler 编译器
     * @return 模型声明
     * @throws Exception 反射调用失败时抛出
     */
    private AgentModelSpec invokeModelSpec(AgentRuntimeCompiler compiler) throws Exception {
        Agent agent = new Agent();
        agent.setModelId(BigInteger.TEN);
        Method method = AgentRuntimeCompiler.class.getDeclaredMethod("buildModelSpec", Agent.class);
        method.setAccessible(true);
        return (AgentModelSpec) method.invoke(compiler, agent);
    }
}
