package com.infoepoch.pms.agent.platform.chat.application;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.action.InterruptionMetadata;
import com.alibaba.cloud.ai.graph.checkpoint.Checkpoint;
import com.infoepoch.pms.agent.platform.chat.application.dto.PendingApprovalResponse;
import com.infoepoch.pms.agent.platform.chat.checkpoint.DatabaseCheckpointStore;
import com.infoepoch.pms.agent.platform.chatbot.domain.Chatbot;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class ApprovalStateServiceTest {

    @Mock
    private DatabaseCheckpointStore checkpointStore;

    @Test
    void shouldIgnorePendingApprovalFromInactiveThread() {
        ApprovalStateService service = new ApprovalStateService(checkpointStore);

        when(checkpointStore.findCandidateThreadIds("session-1_thread_active"))
                .thenReturn(List.of("session-1", "session-1_thread_active"));
        when(checkpointStore.get(any(RunnableConfig.class))).thenAnswer(invocation -> {
            RunnableConfig config = invocation.getArgument(0);
            String threadId = config.threadId().orElse(null);
            if ("session-1".equals(threadId)) {
                return Optional.of(checkpoint("interrupt-old"));
            }
            return Optional.empty();
        });

        PendingApprovalResponse response = service.getPendingApproval("session-1", "session-1_thread_active", chatbot());

        assertFalse(response.isPending());
    }

    @Test
    void shouldDelegateSessionStateCleanupToCheckpointStore() {
        ApprovalStateService service = new ApprovalStateService(checkpointStore);

        service.clearSessionState("session-1", List.of("session-1", "session-1_thread_2"));

        ArgumentCaptor<List<String>> captor = ArgumentCaptor.forClass(List.class);
        verify(checkpointStore).deleteThreadGroups(captor.capture());
        assertEquals(List.of("session-1", "session-1_thread_2"), captor.getValue());
    }

    @Test
    void shouldReadCurrentInterruptionIdFromCheckpointStore() {
        ApprovalStateService service = new ApprovalStateService(checkpointStore);
        when(checkpointStore.findCandidateThreadIds("session-1"))
                .thenReturn(List.of("session-1"));
        when(checkpointStore.get(any(RunnableConfig.class)))
                .thenReturn(Optional.of(checkpoint("interrupt-1")));

        PendingApprovalResponse response = service.getPendingApproval("session-1", chatbot());

        assertTrue(response.isPending());
        assertTrue("interrupt-1".equals(response.getInterruptionId()));
    }

    private Checkpoint checkpoint(String interruptionId) {
        OverAllState state = new OverAllState();
        state.updateState(java.util.Map.of(
                RunnableConfig.HUMAN_FEEDBACK_METADATA_KEY,
                InterruptionMetadata.builder("node-1", new OverAllState())
                        .addToolFeedback(InterruptionMetadata.ToolFeedback.builder()
                                .id("tool-1")
                                .name("submit")
                                .arguments("{\"name\":\"张三\"}")
                                .description("提交审批")
                                .build())
                        .build()
        ));
        return Checkpoint.builder()
                .id(interruptionId)
                .nodeId("node-1")
                .nextNodeId("node-2")
                .state(state.data())
                .build();
    }

    private Chatbot chatbot() {
        LocalDateTime now = LocalDateTime.now();
        return Chatbot.restore(
                "chatbot-1",
                "客服助手",
                "desc",
                null,
                null,
                List.of(),
                20,
                true,
                now,
                now,
                Set.of()
        );
    }
}
