package tech.easyflow.ai.entity;

import com.easyagents.core.message.SystemMessage;
import com.easyagents.core.message.UserMessage;
import com.easyagents.core.model.chat.BaseChatModel;
import com.easyagents.core.model.chat.ChatConfig;
import com.easyagents.core.model.chat.ChatMessageContentFormat;
import com.easyagents.core.model.client.OpenAIChatMessageSerializer;
import org.junit.Assert;
import org.junit.Test;

import java.util.List;
import java.util.Map;

/**
 * 模型高级配置向工作流聊天模型透传的消息格式测试。
 */
public class ModelMessageContentFormatTest {

    /**
     * 验证 OpenAI-compatible、DeepSeek 与 Ollama 模型都会接收内容块数组配置。
     */
    @Test
    public void shouldApplyTextPartsFormatToOpenAiCompatibleModels() {
        Map<String, Object> options = Map.of("agentMessageContentFormat", "TEXT_PARTS");

        Assert.assertEquals(ChatMessageContentFormat.TEXT_PARTS,
                chatConfig(model("custom", options)).getMessageContentFormat());
        Assert.assertEquals(ChatMessageContentFormat.TEXT_PARTS,
                chatConfig(model("deepseek", options)).getMessageContentFormat());
        Assert.assertEquals(ChatMessageContentFormat.TEXT_PARTS,
                chatConfig(model("ollama", options)).getMessageContentFormat());
    }

    /**
     * 验证旧 system 内容块配置会迁移到消息级内容块格式。
     */
    @Test
    public void shouldMigrateLegacySystemTextPartsFormat() {
        Model model = model("custom", Map.of("agentSystemContentFormat", "TEXT_PARTS"));

        Assert.assertEquals(ChatMessageContentFormat.TEXT_PARTS,
                chatConfig(model).getMessageContentFormat());
    }

    /**
     * 验证新旧配置并存时使用新的消息级配置。
     */
    @Test
    public void shouldPreferCurrentMessageFormatSetting() {
        Model model = model("custom", Map.of(
                "agentMessageContentFormat", "STANDARD",
                "agentSystemContentFormat", "TEXT_PARTS"));

        Assert.assertEquals(ChatMessageContentFormat.STANDARD,
                chatConfig(model).getMessageContentFormat());
    }

    /**
     * 验证非法配置会安全回退到标准格式。
     */
    @Test
    public void shouldFallbackToStandardForUnknownFormat() {
        Model model = model("custom", Map.of("agentMessageContentFormat", "PARTS"));

        Assert.assertEquals(ChatMessageContentFormat.STANDARD,
                chatConfig(model).getMessageContentFormat());
    }

    /**
     * 验证工作流选择内容块模式模型后，请求消息按数组格式序列化。
     */
    @Test
    public void shouldSerializeWorkflowModelMessagesAsTextParts() {
        ChatConfig config = chatConfig(model(
                "custom", Map.of("agentMessageContentFormat", "TEXT_PARTS")));

        List<Map<String, Object>> messages = new OpenAIChatMessageSerializer().serializeMessages(
                List.of(SystemMessage.of("系统提示"), new UserMessage("用户问题")),
                config);

        assertTextPart(messages.get(0), "系统提示");
        assertTextPart(messages.get(1), "用户问题");
    }

    /**
     * 创建指定供应商和高级配置的聊天模型记录。
     *
     * @param providerType 供应商类型
     * @param options 模型高级配置
     * @return 模型记录
     */
    private Model model(String providerType, Map<String, Object> options) {
        ModelProvider provider = new ModelProvider();
        provider.setProviderType(providerType);
        provider.setProviderName(providerType);

        Model model = new Model();
        model.setModelProvider(provider);
        model.setEndpoint("https://model.example.com");
        model.setApiKey("sk-test");
        model.setModelName("test-model");
        model.setRequestPath("/v1/chat/completions");
        model.setOptions(options);
        return model;
    }

    /**
     * 获取模型生成的聊天配置。
     *
     * @param model 模型记录
     * @return 聊天配置
     */
    private ChatConfig chatConfig(Model model) {
        return ((BaseChatModel<?>) model.toChatModel()).getConfig();
    }

    /**
     * 断言消息 content 只包含指定文本内容块。
     *
     * @param message 已序列化消息
     * @param expectedText 预期文本
     */
    private void assertTextPart(Map<String, Object> message, String expectedText) {
        List<?> content = (List<?>) message.get("content");
        Assert.assertEquals(1, content.size());
        Map<?, ?> textPart = (Map<?, ?>) content.get(0);
        Assert.assertEquals("text", textPart.get("type"));
        Assert.assertEquals(expectedText, textPart.get("text"));
    }
}
