package com.easyagents.agui;

import com.easyagents.agent.runtime.event.AgentRuntimeEvent;
import com.easyagents.agent.runtime.event.AgentRuntimeEventType;
import io.agentscope.core.agui.event.AguiEvent;
import org.junit.Assert;
import org.junit.Test;

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

/**
 * {@link AguiRuntimeEventProjector} 的协议顺序与终态测试。
 */
public class AguiRuntimeEventProjectorTest {

    /**
     * 验证文本、推理、工具和成功终态按 AG-UI 顺序投影。
     */
    @Test
    public void shouldProjectSuccessfulRunInProtocolOrder() {
        AguiRuntimeEventProjector projector = new AguiRuntimeEventProjector("thread-1", "run-1");
        List<Object> events = new ArrayList<>();

        events.addAll(projector.project(event(AgentRuntimeEventType.STARTED, null, null, Map.of())));
        events.addAll(projector.project(event(
                AgentRuntimeEventType.REASONING_STARTED, "reasoning-1", null, Map.of())));
        events.addAll(projector.project(event(
                AgentRuntimeEventType.REASONING_DELTA, "reasoning-1", null, Map.of("reasoning", "分析"))));
        events.addAll(projector.project(event(
                AgentRuntimeEventType.REASONING_COMPLETED, "reasoning-1", null, Map.of())));
        events.addAll(projector.project(event(
                AgentRuntimeEventType.MESSAGE_DELTA, "message-1", null, Map.of("text", "你好"))));
        events.addAll(projector.project(event(
                AgentRuntimeEventType.TOOL_CALL, null, "tool-1",
                Map.of("toolName", "search", "input", Map.of("q", "AG-UI")))));
        events.addAll(projector.project(event(
                AgentRuntimeEventType.TOOL_RESULT, null, "tool-1", Map.of("text", "done"))));
        events.addAll(projector.project(event(AgentRuntimeEventType.COMPLETED, null, null, Map.of())));

        Assert.assertEquals(List.of(
                "RunStarted",
                "ReasoningMessageStart",
                "ReasoningMessageContent",
                "ReasoningMessageEnd",
                "TextMessageStart",
                "TextMessageContent",
                "ToolCallStart",
                "ToolCallArgs",
                "ToolCallEnd",
                "ToolCallResult",
                "TextMessageEnd",
                "RunFinished"), events.stream().map(value -> value.getClass().getSimpleName()).toList());
        Assert.assertEquals(
                "reasoning", ((AguiEvent.ReasoningMessageStart) events.get(1)).role());
        Assert.assertTrue(projector.isTerminated());
    }

    /**
     * 验证失败终态不会追加成功事件，终态后的迟到事件会被丢弃。
     */
    @Test
    public void shouldEmitSingleErrorTerminalAndIgnoreLateEvents() {
        AguiRuntimeEventProjector projector = new AguiRuntimeEventProjector("thread-1", "run-1");

        List<Object> failed = projector.project(event(
                AgentRuntimeEventType.FAILED, null, null, Map.of("message", "boom")));
        List<Object> late = projector.project(event(AgentRuntimeEventType.COMPLETED, null, null, Map.of()));

        Assert.assertEquals(2, failed.size());
        Assert.assertTrue(failed.get(0) instanceof AguiEvent.RunStarted);
        Assert.assertEquals(
                new AguiExtendedEvent.RunError("thread-1", "run-1", "boom", "AGENT_RUNTIME_FAILED"),
                failed.get(1));
        Assert.assertTrue(late.isEmpty());
    }

    private static AgentRuntimeEvent event(
            AgentRuntimeEventType type,
            String messageId,
            String toolCallId,
            Map<String, Object> payload) {
        AgentRuntimeEvent event = AgentRuntimeEvent.of(type);
        event.setMessageId(messageId);
        event.setToolCallId(toolCallId);
        event.setPayload(payload);
        return event;
    }
}
