package com.ecep.contract.service;

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.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.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.MockitoAnnotations;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

/**
 * WebSocketServerCallbackManager的测试类，用于验证WebSocket服务组件的功能
 */
class WebSocketServerCallbackManagerTest {

    @Mock
    private ObjectMapper objectMapper;

    @InjectMocks
    private WebSocketServerCallbackManager callbackManager;

    @Mock
    private SessionInfo sessionInfo;

    private ObjectMapper realObjectMapper;

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

    /**
     * 测试handleAsMessageCallback方法，验证正确处理findAll消息
     */
    @Test
    void testHandleAsMessageCallback_FindAll() throws Exception {
        // 准备测试数据
        ObjectNode jsonNode = realObjectMapper.createObjectNode();
        jsonNode.put(WebSocketConstant.MESSAGE_ID_FIELD_NAME, "test-message-id");
        jsonNode.put(WebSocketConstant.SERVICE_FIELD_NAME, "mockService");
        jsonNode.put(WebSocketConstant.METHOD_FIELD_NAME, "findAll");
        
        // 创建参数数组
        ArrayNode argumentsNode = realObjectMapper.createArrayNode();
        ObjectNode paramsNode = realObjectMapper.createObjectNode();
        paramsNode.put("searchText", "test");
        argumentsNode.add(paramsNode);
        
        ObjectNode pageableNode = realObjectMapper.createObjectNode();
        pageableNode.put("pageNumber", 0);
        pageableNode.put("pageSize", 10);
        argumentsNode.add(pageableNode);
        
        jsonNode.set(WebSocketConstant.ARGUMENTS_FIELD_NAME, argumentsNode);
        
        // 创建模拟服务
        MockQueryService mockService = mock(MockQueryService.class);
        List<MockVo> voList = new ArrayList<>();
        MockVo mockVo = new MockVo();
        mockVo.setId(1);
        mockVo.setName("test-name");
        voList.add(mockVo);
        
        Page<MockVo> page = new PageImpl<>(voList);
        when(mockService.findAll(any(JsonNode.class), any(Pageable.class))).thenReturn(page);
        
        // 模拟SpringApp.getBean
        try (MockedStatic<SpringApp> mockedStatic = mockStatic(SpringApp.class)) {
            mockedStatic.when(() -> SpringApp.getBean("mockService")).thenReturn(mockService);
            
            // 模拟objectMapper.treeToValue
            when(objectMapper.treeToValue(pageableNode, PageArgument.class)).thenReturn(new PageArgument());
            
            // 使用反射调用私有方法
            Method method = WebSocketServerCallbackManager.class.getDeclaredMethod(
                "handleAsMessageCallback", SessionInfo.class, String.class, JsonNode.class);
            method.setAccessible(true);
            Object result = method.invoke(callbackManager, sessionInfo, "test-message-id", jsonNode);
            
            // 验证结果
            assertNotNull(result);
            assertTrue(result instanceof PageContent);
            
            // 验证方法调用
            verify(mockService, times(1)).findAll(any(JsonNode.class), any(Pageable.class));
        }
    }

    /**
     * 测试handleAsMessageCallback方法，验证正确处理findById消息
     */
    @Test
    void testHandleAsMessageCallback_FindById() throws Exception {
        // 准备测试数据
        ObjectNode jsonNode = realObjectMapper.createObjectNode();
        jsonNode.put(WebSocketConstant.MESSAGE_ID_FIELD_NAME, "test-message-id");
        jsonNode.put(WebSocketConstant.SERVICE_FIELD_NAME, "mockService");
        jsonNode.put(WebSocketConstant.METHOD_FIELD_NAME, "findById");
        
        // 创建参数数组
        ArrayNode argumentsNode = realObjectMapper.createArrayNode();
        argumentsNode.add(1); // ID参数
        
        jsonNode.set(WebSocketConstant.ARGUMENTS_FIELD_NAME, argumentsNode);
        
        // 创建模拟服务
        MockEntityService mockService = mock(MockEntityService.class);
        MockModel mockModel = new MockModel();
        mockModel.setId(1);
        mockModel.setName("test-name");
        
        when(mockService.getById(1)).thenReturn(mockModel);
        
        // 模拟SpringApp.getBean
        try (MockedStatic<SpringApp> mockedStatic = mockStatic(SpringApp.class)) {
            mockedStatic.when(() -> SpringApp.getBean("mockService")).thenReturn(mockService);
            
            // 使用反射调用私有方法
            Method method = WebSocketServerCallbackManager.class.getDeclaredMethod(
                "handleAsMessageCallback", SessionInfo.class, String.class, JsonNode.class);
            method.setAccessible(true);
            Object result = method.invoke(callbackManager, sessionInfo, "test-message-id", jsonNode);
            
            // 验证结果
            assertNotNull(result);
            assertEquals(mockModel, result);
            
            // 验证方法调用
            verify(mockService, times(1)).getById(1);
        }
    }

    /**
     * 测试handleAsMessageCallback方法，验证正确处理save消息
     */
    @Test
    void testHandleAsMessageCallback_Save() throws Exception {
        // 准备测试数据
        ObjectNode jsonNode = realObjectMapper.createObjectNode();
        jsonNode.put(WebSocketConstant.MESSAGE_ID_FIELD_NAME, "test-message-id");
        jsonNode.put(WebSocketConstant.SERVICE_FIELD_NAME, "mockService");
        jsonNode.put(WebSocketConstant.METHOD_FIELD_NAME, "save");
        
        // 创建参数数组
        ArrayNode argumentsNode = realObjectMapper.createArrayNode();
        ObjectNode paramsNode = realObjectMapper.createObjectNode();
        paramsNode.put("name", "test-name");
        argumentsNode.add(paramsNode);
        argumentsNode.add("com.ecep.contract.service.WebSocketServerCallbackManagerTest$MockVo"); // 类型参数（内部类使用$符号）
        
        jsonNode.set(WebSocketConstant.ARGUMENTS_FIELD_NAME, argumentsNode);
        
        // 创建具体服务实现
        ConcreteMockEntityService mockService = new ConcreteMockEntityService();
        MockModel mockModel = new MockModel();
        mockModel.setId(1);
        mockModel.setName("test-name");
        
        // 模拟SpringApp.getBean
        try (MockedStatic<SpringApp> mockedStatic = mockStatic(SpringApp.class)) {
            mockedStatic.when(() -> SpringApp.getBean("mockService")).thenReturn(mockService);
            
            // 模拟objectMapper.treeToValue和updateValue
            MockVo mockVo = new MockVo();
            mockVo.setName("test-name");
            when(objectMapper.convertValue(paramsNode, MockVo.class)).thenReturn(mockVo);
            
            // 使用反射调用私有方法
            Method method = WebSocketServerCallbackManager.class.getDeclaredMethod(
                "handleAsMessageCallback", SessionInfo.class, String.class, JsonNode.class);
            method.setAccessible(true);
            Object result = method.invoke(callbackManager, sessionInfo, "test-message-id", jsonNode);
            
            // 验证结果
            assertNotNull(result);
            assertTrue(result instanceof MockModel);
            assertEquals(mockModel.getName(), ((MockModel)result).getName());
        }
    }

    /**
     * 测试handleAsMessageCallback方法，验证正确处理delete消息
     */
    @Test
    void testHandleAsMessageCallback_Delete() throws Exception {
        // 准备测试数据
        ObjectNode jsonNode = realObjectMapper.createObjectNode();
        jsonNode.put(WebSocketConstant.MESSAGE_ID_FIELD_NAME, "test-message-id");
        jsonNode.put(WebSocketConstant.SERVICE_FIELD_NAME, "mockService");
        jsonNode.put(WebSocketConstant.METHOD_FIELD_NAME, "delete");
        
        // 创建参数数组
        ArrayNode argumentsNode = realObjectMapper.createArrayNode();
        ObjectNode paramsNode = realObjectMapper.createObjectNode();
        paramsNode.put("id", 1);
        argumentsNode.add(paramsNode);
        
        jsonNode.set(WebSocketConstant.ARGUMENTS_FIELD_NAME, argumentsNode);
        
        // 创建模拟服务
        MockEntityService mockService = mock(MockEntityService.class);
        MockModel mockModel = new MockModel();
        mockModel.setId(1);
        mockModel.setName("test-name");
        
        when(mockService.getById(1)).thenReturn(mockModel);
        doNothing().when(mockService).delete(mockModel);
        
        // 模拟SpringApp.getBean
        try (MockedStatic<SpringApp> mockedStatic = mockStatic(SpringApp.class)) {
            mockedStatic.when(() -> SpringApp.getBean("mockService")).thenReturn(mockService);
            
            // 使用反射调用私有方法
            Method method = WebSocketServerCallbackManager.class.getDeclaredMethod(
                "handleAsMessageCallback", SessionInfo.class, String.class, JsonNode.class);
            method.setAccessible(true);
            Object result = method.invoke(callbackManager, sessionInfo, "test-message-id", jsonNode);
            
            // 验证结果
            assertNotNull(result);
            assertEquals(mockModel, result);
            
            // 验证方法调用
            verify(mockService, times(1)).getById(1);
            verify(mockService, times(1)).delete(mockModel);
        }
    }

    /**
     * 测试send方法，验证消息发送功能
     */
    @Test
    void testSend() throws Exception {
        // 准备测试数据
        MockModel mockModel = new MockModel();
        mockModel.setId(1);
        mockModel.setName("test-name");
        
        // 使用反射调用私有方法
        Method method = WebSocketServerCallbackManager.class.getDeclaredMethod(
            "send", SessionInfo.class, String.class, Object.class);
        method.setAccessible(true);
        method.invoke(callbackManager, sessionInfo, "test-message-id", mockModel);
        
        // 验证方法调用
        Map<String, Object> expectedMap = new HashMap<>();
        expectedMap.put("data", mockModel);
        expectedMap.put(WebSocketConstant.MESSAGE_ID_FIELD_NAME, "test-message-id");
        expectedMap.put(WebSocketConstant.SUCCESS_FIELD_NAME, true);
        
        verify(sessionInfo, times(1)).send(expectedMap);
    }

    /**
     * 测试send方法，验证Voable对象的处理
     */
    @Test
    void testSend_Voable() throws Exception {
        // 准备测试数据
        MockModelWithVo mockModel = new MockModelWithVo();
        mockModel.setId(1);
        mockModel.setName("test-name");
        
        // 使用反射调用私有方法
        Method method = WebSocketServerCallbackManager.class.getDeclaredMethod(
            "send", SessionInfo.class, String.class, Object.class);
        method.setAccessible(true);
        method.invoke(callbackManager, sessionInfo, "test-message-id", mockModel);
        
        // 使用ArgumentCaptor捕获实际传入的参数
        ArgumentCaptor<Map<String, Object>> captor = ArgumentCaptor.forClass(Map.class);
        verify(sessionInfo, times(1)).send(captor.capture());
        
        // 验证捕获的参数
        Map<String, Object> actualMap = captor.getValue();
        assertEquals("test-message-id", actualMap.get(WebSocketConstant.MESSAGE_ID_FIELD_NAME));
        assertEquals(true, actualMap.get(WebSocketConstant.SUCCESS_FIELD_NAME));
        
        // 验证data字段是MockVo类型
        assertTrue(actualMap.get("data") instanceof MockVo);
        MockVo actualVo = (MockVo) actualMap.get("data");
        
        // 验证MockVo的内容
        MockVo expectedVo = mockModel.toVo();
        assertEquals(expectedVo.getId(), actualVo.getId());
        assertEquals(expectedVo.getName(), actualVo.getName());
    }

    /**
     * 测试createNewEntity方法，验证新实体创建功能
     */
    @Test
    void testCreateNewEntity() throws Exception {
        // 创建模拟服务
        ConcreteMockEntityService mockService = new ConcreteMockEntityService();
        
        // 使用反射获取createNewEntity方法
        Method method = WebSocketServerCallbackManager.class.getDeclaredMethod("createNewEntity", IEntityService.class);
        method.setAccessible(true);
        
        // 执行方法
        Object result = method.invoke(callbackManager, mockService);
        
        // 验证结果
        assertNotNull(result);
        assertTrue(result instanceof MockModel);
    }

    /**
     * 测试getTargetClass方法，验证获取原始类功能
     */
    @Test
    void testGetTargetClass() throws Exception {
        // 创建模拟CGLIB代理类
        Class<?> cglibProxyClass = createMockCglibProxyClass();
        
        // 使用反射获取getTargetClass方法
        Method method = WebSocketServerCallbackManager.class.getDeclaredMethod("getTargetClass", Class.class);
        method.setAccessible(true);
        
        // 执行方法
        Class<?> result = (Class<?>) method.invoke(callbackManager, cglibProxyClass);
        
        // 验证结果
        assertNotNull(result);
        assertEquals(MockModel.class, result);
    }

    /**
     * 模拟的QueryService实现
     */
    private interface MockQueryService extends QueryService<MockVo> {
        @Override
        Page<MockVo> findAll(JsonNode paramsNode, Pageable pageable);
        
        @Override
        MockVo findById(Integer id);
    }

    /**
     * 模拟的IEntityService实现
     */
    private interface MockEntityService extends IEntityService<MockModel>, VoableService<MockModel, MockVo> {
        @Override
        MockModel getById(Integer id);
        
        @Override
        Page<MockModel> findAll(Specification<MockModel> spec, Pageable pageable);
        
        @Override
        Specification<MockModel> getSpecification(String searchText);
        
        @Override
        void delete(MockModel entity);
        
        @Override
        MockModel save(MockModel entity);
        
        @Override
        void updateByVo(MockModel model, MockVo vo);
    }

    /**
     * 具体的MockEntityService实现，用于测试createNewEntity方法
     */
    private static class ConcreteMockEntityService implements IEntityService<MockModel>, VoableService<MockModel, MockVo> {
        @Override
        public MockModel getById(Integer id) {
            return null;
        }
        
        @Override
        public Page<MockModel> findAll(Specification<MockModel> spec, Pageable pageable) {
            return null;
        }
        
        @Override
        public Specification<MockModel> getSpecification(String searchText) {
            return null;
        }
        
        @Override
        public void delete(MockModel entity) {
        }
        
        @Override
        public MockModel save(MockModel entity) {
            return entity; // 返回传入的实体对象
        }
        
        @Override
        public void updateByVo(MockModel model, MockVo vo) {
            if (model != null && vo != null) {
                model.setName(vo.getName());
                if (vo.getId() != null) {
                    model.setId(vo.getId());
                }
            }
        }
    }

    /**
     * 模拟的模型类
     */
    public static class MockModel {
        private Integer id;
        private String name;
        
        public Integer getId() {
            return id;
        }
        
        public void setId(Integer id) {
            this.id = id;
        }
        
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
    }

    /**
     * 模拟的VO类
     */
    private static class MockVo {
        private Integer id;
        private String name;
        
        public Integer getId() {
            return id;
        }
        
        public void setId(Integer id) {
            this.id = id;
        }
        
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
    }

    /**
     * 实现了Voable接口的模拟模型类
     */
    private static class MockModelWithVo extends MockModel implements Voable<MockVo> {
        @Override
        public MockVo toVo() {
            MockVo vo = new MockVo();
            vo.setId(getId());
            vo.setName(getName());
            return vo;
        }
    }

    /**
     * 创建模拟的CGLIB代理类
     */
    private Class<?> createMockCglibProxyClass() {
        // 这里创建一个简单的模拟CGLIB代理类，实际项目中可能需要更复杂的实现
        return MockModel$$SpringCGLIB$$0.class;
    }
    
    /**
     * 模拟的CGLIB代理类
     */
    private static class MockModel$$SpringCGLIB$$0 extends MockModel {
    }
}