package com.easyagents.core.test.model.client;

import com.easyagents.core.message.AiMessage;
import com.easyagents.core.message.SystemMessage;
import com.easyagents.core.message.ToolCall;
import com.easyagents.core.message.ToolMessage;
import com.easyagents.core.message.UserMessage;
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;

/**
 * OpenAI-compatible 多模态消息序列化测试。
 */
public class OpenAIChatMessageSerializerTest {

    /**
     * 验证标准模式继续使用原有纯文本字符串格式。
     */
    @Test
    public void shouldKeepStringContentInStandardMode() {
        ToolMessage toolMessage = toolMessage("call-1", "工具结果");

        List<Map<String, Object>> messages = new OpenAIChatMessageSerializer()
                .serializeMessages(List.of(
                        SystemMessage.of("系统提示"),
                        new UserMessage("用户问题"),
                        new AiMessage("助手回答"),
                        toolMessage
                ), new ChatConfig());

        Assert.assertEquals("系统提示", messages.get(0).get("content"));
        Assert.assertEquals("用户问题", messages.get(1).get("content"));
        Assert.assertEquals("助手回答", messages.get(2).get("content"));
        Assert.assertEquals("工具结果", messages.get(3).get("content"));
    }

    /**
     * 验证内容块模式会转换全部纯文本消息角色。
     */
    @Test
    public void shouldSerializeAllTextRolesAsContentParts() {
        ChatConfig config = textPartsConfig();
        ToolMessage toolMessage = toolMessage("call-1", "工具结果");

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

        assertTextPart(messages.get(0), "系统提示");
        assertTextPart(messages.get(1), "用户问题");
        assertTextPart(messages.get(2), "助手回答");
        assertTextPart(messages.get(3), "工具结果");
        Assert.assertEquals("call-1", messages.get(3).get("tool_call_id"));
    }

    /**
     * 验证 Data URI 会写入标准的 image_url.url 字段。
     */
    @Test
    public void shouldSerializeImageDataUriIntoImageUrlField() {
        String dataUri = "data:image/png;base64,AQID";
        UserMessage message = new UserMessage("识别图片");
        message.addImageUrl(dataUri);

        List<Map<String, Object>> messages = new OpenAIChatMessageSerializer()
                .serializeMessages(List.of(message), new ChatConfig());

        Assert.assertNotNull(messages);
        List<?> content = (List<?>) messages.get(0).get("content");
        Map<?, ?> imageContent = (Map<?, ?>) content.get(1);
        Map<?, ?> imageUrl = (Map<?, ?>) imageContent.get("image_url");
        Assert.assertEquals("image_url", imageContent.get("type"));
        Assert.assertEquals(dataUri, imageUrl.get("url"));
    }

    /**
     * 验证内容块模式保留多模态数组和工具调用结构字段。
     */
    @Test
    public void shouldPreserveStructuredFieldsInTextPartsMode() {
        String dataUri = "data:image/png;base64,AQID";
        UserMessage userMessage = new UserMessage("识别图片");
        userMessage.addImageUrl(dataUri);
        AiMessage assistantMessage = new AiMessage(null);
        assistantMessage.setReasoningContent("先分析");
        assistantMessage.setToolCalls(List.of(
                new ToolCall("call-1", "image_search", "{\"query\":\"license\"}")));
        ToolMessage toolMessage = toolMessage("call-1", "工具结果");

        List<Map<String, Object>> messages = new OpenAIChatMessageSerializer()
                .serializeMessages(List.of(userMessage, assistantMessage, toolMessage), textPartsConfig());

        List<?> userContent = (List<?>) messages.get(0).get("content");
        Assert.assertEquals(2, userContent.size());
        Assert.assertEquals("image_url", ((Map<?, ?>) userContent.get(1)).get("type"));
        assertTextPart(messages.get(1), "");
        Assert.assertEquals("先分析", messages.get(1).get("reasoning_content"));
        Assert.assertTrue(messages.get(1).containsKey("tool_calls"));
        assertTextPart(messages.get(2), "工具结果");
        Assert.assertEquals("call-1", messages.get(2).get("tool_call_id"));
    }

    /**
     * 创建内容块数组模式配置。
     *
     * @return 内容块数组模式配置
     */
    private ChatConfig textPartsConfig() {
        ChatConfig config = new ChatConfig();
        config.setMessageContentFormat(ChatMessageContentFormat.TEXT_PARTS);
        config.setNeedReasoningContentForToolMessage(Boolean.TRUE);
        return config;
    }

    /**
     * 创建工具结果消息。
     *
     * @param toolCallId 工具调用标识
     * @param content 工具结果文本
     * @return 工具结果消息
     */
    private ToolMessage toolMessage(String toolCallId, String content) {
        ToolMessage message = new ToolMessage();
        message.setToolCallId(toolCallId);
        message.setContent(content);
        return message;
    }

    /**
     * 断言消息 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"));
    }
}
