package com.ruoyi.web.kb;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;

import com.ruoyi.web.kb.controller.KbOpenAiProxyController;
import com.ruoyi.web.kb.service.KbOpenAiProxyService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

@ExtendWith(MockitoExtension.class)
@DisplayName("知识库包 /v1 转发 Controller")
class KbOpenAiProxyControllerApiTest
{
    @Mock
    private KbOpenAiProxyService kbOpenAiProxyService;

    @InjectMocks
    private KbOpenAiProxyController controller;

    private MockMvc mockMvc;

    @BeforeEach
    void setUp()
    {
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }

    @Test
    @DisplayName("UT-KB-LLM-007 GET /v1/models")
    void models() throws Exception
    {
        when(kbOpenAiProxyService.listModels())
                .thenReturn(ResponseEntity.ok("{\"data\":[]}".getBytes()));
        mockMvc.perform(get("/v1/models"))
                .andExpect(status().isOk())
                .andExpect(content().json("{\"data\":[]}"));
        verify(kbOpenAiProxyService).listModels();
    }

    @Test
    @DisplayName("POST /v1/chat/completions 非流式")
    void chatNonStream() throws Exception
    {
        when(kbOpenAiProxyService.isStreamRequest(any())).thenReturn(false);
        when(kbOpenAiProxyService.chatCompletions(any()))
                .thenReturn(ResponseEntity.ok("{\"choices\":[]}".getBytes()));
        mockMvc.perform(post("/v1/chat/completions")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content("{\"model\":\"auto\",\"stream\":false}"))
                .andExpect(status().isOk())
                .andExpect(content().json("{\"choices\":[]}"));
        verify(kbOpenAiProxyService).chatCompletions(any());
    }

    @Test
    @DisplayName("POST /v1/chat/completions 流式 SSE")
    void chatStream() throws Exception
    {
        when(kbOpenAiProxyService.isStreamRequest(any())).thenReturn(true);
        doAnswer(invocation -> {
            OutputStream output = invocation.getArgument(1);
            output.write("data: {\"choices\":[]}\n\n".getBytes(StandardCharsets.UTF_8));
            output.flush();
            return null;
        }).when(kbOpenAiProxyService).streamChatCompletions(any(), any());

        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setMethod("POST");
        request.setContentType(MediaType.APPLICATION_JSON_VALUE);
        request.setContent("{\"model\":\"auto\",\"stream\":true}".getBytes(StandardCharsets.UTF_8));
        MockHttpServletResponse response = new MockHttpServletResponse();

        controller.chatCompletions(request, response);

        assertTrue(response.getContentType().startsWith(MediaType.TEXT_EVENT_STREAM_VALUE));
        assertTrue(response.getContentAsString().contains("data:"));
        verify(kbOpenAiProxyService).streamChatCompletions(any(), any());
    }
}
