package com.ecep.contract.integration;

import com.ecep.contract.IEntityService;
import com.ecep.contract.PageArgument;
import com.ecep.contract.PageContent;
import com.ecep.contract.QueryService;
import com.ecep.contract.SpringApp;
import com.ecep.contract.constant.WebSocketConstant;
import com.ecep.contract.handler.SessionInfo;
import com.ecep.contract.model.Voable;
import com.ecep.contract.service.VoableService;
import com.ecep.contract.service.WebSocketServerCallbackManager;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;

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

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.*;

/**
 * WebSocketServerCallbackManager的集成测试类，用于测试与Service层的交互
 */
@SpringBootTest
class WebSocketServerCallbackManagerIntegrationTest {

    @MockBean
    private RedisTemplate<String, Object> redisTemplate;

    @Mock
    private SessionInfo sessionInfo;

    @InjectMocks
    private WebSocketServerCallbackManager callbackManager;

    private ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        objectMapper = new ObjectMapper();
    }

    /**
     * 测试findAll方法的完整流程，包括Service调用、VO转换和缓存
     */
    @Test
    void testFullWorkflow_FindAll() throws Exception {
        // 准备测试数据
        String serviceName = "contractService";
        String methodName = "findAll";
        String messageId = "test-find-all-1";

        // 创建请求JSON
        ObjectNode requestJson = createFindAllRequest(messageId, serviceName, methodName);

        // 模拟SessionInfo的send方法
        doAnswer(invocation -> {
            Object arg = invocation.getArgument(0);
            assertNotNull(arg);
            assertTrue(arg instanceof Map);
            Map<String, Object> response = (Map<String, Object>) arg;
            assertEquals(messageId, response.get(WebSocketConstant.MESSAGE_ID_FIELD_NAME));
            assertTrue((Boolean) response.get(WebSocketConstant.SUCCESS_FIELD_NAME));
            return null;
        }).when(sessionInfo).send(any(Map.class));

        // 执行WebSocket回调
        callbackManager.onMessage(sessionInfo, requestJson);

        // 验证结果
        // onMessage方法返回void，不需要验证返回值


        // 验证SessionInfo的send方法被调用
        verify(sessionInfo, times(1)).send(any(Map.class));
    }

    /**
     * 测试findById方法的完整流程，包括缓存命中和未命中的情况
     */
    @Test
    void testFullWorkflow_FindById_CacheBehavior() throws Exception {
        // 准备测试数据
        String serviceName = "contractService";
        String methodName = "findById";
        String messageId = "test-find-by-id-1";
        Integer id = 1;

        // 第一次调用：缓存未命中
        ObjectNode firstRequestJson = createFindByIdRequest(messageId, serviceName, methodName, id);

        // 模拟Redis缓存未命中
        when(redisTemplate.opsForValue().get(anyString())).thenReturn(null);

        // 模拟SessionInfo的send方法
        doAnswer(invocation -> {
            Object arg = invocation.getArgument(0);
            assertNotNull(arg);
            assertTrue(arg instanceof Map);
            Map<String, Object> response = (Map<String, Object>) arg;
            assertEquals(messageId, response.get(WebSocketConstant.MESSAGE_ID_FIELD_NAME));
            assertTrue((Boolean) response.get(WebSocketConstant.SUCCESS_FIELD_NAME));
            return null;
        }).when(sessionInfo).send(any(Map.class));

        // 执行第一次调用
        callbackManager.onMessage(sessionInfo, firstRequestJson);

        // 验证Redis操作
        verify(redisTemplate, times(1)).opsForValue().get(anyString());
        verify(redisTemplate, times(1)).opsForValue().set(anyString(), any(), anyLong(), any());

        // 重置mock对象
        reset(redisTemplate);
        reset(sessionInfo);

        // 第二次调用：缓存命中
        String secondMessageId = "test-find-by-id-2";
        ObjectNode secondRequestJson = createFindByIdRequest(secondMessageId, serviceName, methodName, id);

        // 模拟Redis缓存命中
        Map<String, Object> mockCacheValue = new HashMap<>();
        mockCacheValue.put("id", id);
        mockCacheValue.put("name", "Mock Contract");
        when(redisTemplate.opsForValue().get(anyString())).thenReturn(mockCacheValue);

        // 模拟SessionInfo的send方法
        doAnswer(invocation -> {
            Object arg = invocation.getArgument(0);
            assertNotNull(arg);
            assertTrue(arg instanceof Map);
            Map<String, Object> response = (Map<String, Object>) arg;
            assertEquals(secondMessageId, response.get(WebSocketConstant.MESSAGE_ID_FIELD_NAME));
            assertTrue((Boolean) response.get(WebSocketConstant.SUCCESS_FIELD_NAME));
            return null;
        }).when(sessionInfo).send(any(Map.class));

        // 执行第二次调用
        callbackManager.onMessage(sessionInfo, secondRequestJson);

        // 验证Redis操作
        verify(redisTemplate, times(1)).opsForValue().get(anyString());
        verify(redisTemplate, times(0)).opsForValue().set(anyString(), any(), anyLong(), any());
    }

    /**
     * 测试save方法的完整流程，包括实体保存、VO转换和缓存清理
     */
    @Test
    void testFullWorkflow_Save() throws Exception {
        // 准备测试数据
        String serviceName = "contractService";
        String methodName = "save";
        String messageId = "test-save-1";

        // 创建请求JSON
        ObjectNode requestJson = createSaveRequest(messageId, serviceName, methodName);

        // 模拟SessionInfo的send方法
        doAnswer(invocation -> {
            Object arg = invocation.getArgument(0);
            assertNotNull(arg);
            assertTrue(arg instanceof Map);
            Map<String, Object> response = (Map<String, Object>) arg;
            assertEquals(messageId, response.get(WebSocketConstant.MESSAGE_ID_FIELD_NAME));
            assertTrue((Boolean) response.get(WebSocketConstant.SUCCESS_FIELD_NAME));
            return null;
        }).when(sessionInfo).send(any(Map.class));

        // 执行WebSocket回调
        callbackManager.onMessage(sessionInfo, requestJson);

        // 验证SessionInfo的send方法被调用
        verify(sessionInfo, times(1)).send(any(Map.class));
        // 验证Redis缓存清理操作
        // 在实际的Service实现中应该有缓存清理逻辑
    }

    /**
     * 测试delete方法的完整流程，包括实体删除和缓存清理
     */
    @Test
    void testFullWorkflow_Delete() throws Exception {
        // 准备测试数据
        String serviceName = "contractService";
        String methodName = "delete";
        String messageId = "test-delete-1";
        Integer id = 1;

        // 创建请求JSON
        ObjectNode requestJson = createDeleteRequest(messageId, serviceName, methodName, id);

        // 模拟SessionInfo的send方法
        doAnswer(invocation -> {
            Object arg = invocation.getArgument(0);
            assertNotNull(arg);
            assertTrue(arg instanceof Map);
            Map<String, Object> response = (Map<String, Object>) arg;
            assertEquals(messageId, response.get(WebSocketConstant.MESSAGE_ID_FIELD_NAME));
            assertTrue((Boolean) response.get(WebSocketConstant.SUCCESS_FIELD_NAME));
            return null;
        }).when(sessionInfo).send(any(Map.class));

        // 执行WebSocket回调
        callbackManager.onMessage(sessionInfo, requestJson);

        // 验证SessionInfo的send方法被调用
        verify(sessionInfo, times(1)).send(any(Map.class));
        // 验证Redis缓存清理操作
        // 在实际的Service实现中应该有缓存清理逻辑
    }

    /**
     * 测试错误处理机制
     */
    @Test
    void testErrorHandling() throws Exception {
        // 准备测试数据 - 无效的JSON
        String invalidJson = "{invalid json}";

        // 模拟SessionInfo的send方法
        doAnswer(invocation -> {
            Object arg = invocation.getArgument(0);
            assertNotNull(arg);
            assertTrue(arg instanceof Map);
            Map<String, Object> response = (Map<String, Object>) arg;
            assertFalse((Boolean) response.get("success"));
            assertNotNull(response.get("error"));
            return null;
        }).when(sessionInfo).send(any(Map.class));

        // 执行WebSocket回调
        callbackManager.onMessage(sessionInfo, objectMapper.readTree(invalidJson));

        // 验证SessionInfo的send方法被调用
        verify(sessionInfo, times(1)).send(any(Map.class));
    }

    /**
     * 创建findAll请求JSON
     */
    private ObjectNode createFindAllRequest(String messageId, String serviceName, String methodName) {
        ObjectNode requestJson = objectMapper.createObjectNode();
        requestJson.put(WebSocketConstant.MESSAGE_ID_FIELD_NAME, messageId);
        requestJson.put(WebSocketConstant.SERVICE_FIELD_NAME, serviceName);
        requestJson.put(WebSocketConstant.METHOD_FIELD_NAME, methodName);

        ArrayNode argumentsNode = objectMapper.createArrayNode();
        ObjectNode paramsNode = objectMapper.createObjectNode();
        paramsNode.put("searchText", "test");
        argumentsNode.add(paramsNode);

        ObjectNode pageableNode = objectMapper.createObjectNode();
        pageableNode.put("pageNumber", 0);
        pageableNode.put("pageSize", 10);
        argumentsNode.add(pageableNode);

        requestJson.set(WebSocketConstant.ARGUMENTS_FIELD_NAME, argumentsNode);
        return requestJson;
    }

    /**
     * 创建findById请求JSON
     */
    private ObjectNode createFindByIdRequest(String messageId, String serviceName, String methodName, Integer id) {
        ObjectNode requestJson = objectMapper.createObjectNode();
        requestJson.put(WebSocketConstant.MESSAGE_ID_FIELD_NAME, messageId);
        requestJson.put(WebSocketConstant.SERVICE_FIELD_NAME, serviceName);
        requestJson.put(WebSocketConstant.METHOD_FIELD_NAME, methodName);

        ArrayNode argumentsNode = objectMapper.createArrayNode();
        argumentsNode.add(id);

        requestJson.set(WebSocketConstant.ARGUMENTS_FIELD_NAME, argumentsNode);
        return requestJson;
    }

    /**
     * 创建save请求JSON
     */
    private ObjectNode createSaveRequest(String messageId, String serviceName, String methodName) {
        ObjectNode requestJson = objectMapper.createObjectNode();
        requestJson.put(WebSocketConstant.MESSAGE_ID_FIELD_NAME, messageId);
        requestJson.put(WebSocketConstant.SERVICE_FIELD_NAME, serviceName);
        requestJson.put(WebSocketConstant.METHOD_FIELD_NAME, methodName);

        ArrayNode argumentsNode = objectMapper.createArrayNode();
        ObjectNode paramsNode = objectMapper.createObjectNode();
        paramsNode.put("name", "Test Contract");
        paramsNode.put("code", "CONTRACT-001");
        argumentsNode.add(paramsNode);
        argumentsNode.add("com.ecep.contract.model.ContractVo"); // 类型参数

        requestJson.set(WebSocketConstant.ARGUMENTS_FIELD_NAME, argumentsNode);
        return requestJson;
    }

    /**
     * 创建delete请求JSON
     */
    private ObjectNode createDeleteRequest(String messageId, String serviceName, String methodName, Integer id) {
        ObjectNode requestJson = objectMapper.createObjectNode();
        requestJson.put(WebSocketConstant.MESSAGE_ID_FIELD_NAME, messageId);
        requestJson.put(WebSocketConstant.SERVICE_FIELD_NAME, serviceName);
        requestJson.put(WebSocketConstant.METHOD_FIELD_NAME, methodName);

        ArrayNode argumentsNode = objectMapper.createArrayNode();
        ObjectNode paramsNode = objectMapper.createObjectNode();
        paramsNode.put("id", id);
        argumentsNode.add(paramsNode);

        requestJson.set(WebSocketConstant.ARGUMENTS_FIELD_NAME, argumentsNode);
        return requestJson;
    }
}