package com.mosquito.project.dto;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * ActivityGraphResponse DTO测试
 */
@DisplayName("ActivityGraphResponse DTO测试")
class ActivityGraphResponseTest {

    private ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        objectMapper = new ObjectMapper();
    }

    @Nested
    @DisplayName("构造函数测试")
    class ConstructorTests {

        @Test
        @DisplayName("全参数构造函数应该正确设置所有字段")
        void shouldSetAllFieldsCorrectly_WhenUsingAllArgsConstructor() {
            // Given
            List<ActivityGraphResponse.Node> nodes = createNodes();
            List<ActivityGraphResponse.Edge> edges = createEdges();

            // When
            ActivityGraphResponse response = new ActivityGraphResponse(nodes, edges);

            // Then
            assertThat(response.getNodes()).isEqualTo(nodes);
            assertThat(response.getEdges()).isEqualTo(edges);
        }

        @Test
        @DisplayName("空列表构造函数应该正确处理")
        void shouldHandleEmptyList_WhenUsingConstructor() {
            // Given
            List<ActivityGraphResponse.Node> emptyNodes = Collections.emptyList();
            List<ActivityGraphResponse.Edge> emptyEdges = Collections.emptyList();

            // When
            ActivityGraphResponse response = new ActivityGraphResponse(emptyNodes, emptyEdges);

            // Then
            assertThat(response.getNodes()).isEmpty();
            assertThat(response.getEdges()).isEmpty();
        }

        @Test
        @DisplayName("null值构造函数应该正确处理")
        void shouldHandleNullValues_WhenUsingConstructor() {
            // When
            ActivityGraphResponse response = new ActivityGraphResponse(null, null);

            // Then
            assertThat(response.getNodes()).isNull();
            assertThat(response.getEdges()).isNull();
        }

        @Test
        @DisplayName("混合null和非null构造函数应该正确处理")
        void shouldHandleMixedNullAndNonNull_WhenUsingConstructor() {
            // Given
            List<ActivityGraphResponse.Node> nodes = createNodes();

            // When
            ActivityGraphResponse response = new ActivityGraphResponse(nodes, null);

            // Then
            assertThat(response.getNodes()).isEqualTo(nodes);
            assertThat(response.getEdges()).isNull();
        }
    }

    @Nested
    @DisplayName("Getter和Setter测试")
    class GetterSetterTests {

        private ActivityGraphResponse response;

        @BeforeEach
        void setUp() {
            response = new ActivityGraphResponse(Collections.emptyList(), Collections.emptyList());
        }

        @Test
        @DisplayName("nodes字段的getter和setter应该正常工作")
        void shouldWorkCorrectly_NodesGetterSetter() {
            // Given
            List<ActivityGraphResponse.Node> nodes = createNodes();

            // When
            response.setNodes(nodes);

            // Then
            assertThat(response.getNodes()).isEqualTo(nodes);
        }

        @Test
        @DisplayName("edges字段的getter和setter应该正常工作")
        void shouldWorkCorrectly_EdgesGetterSetter() {
            // Given
            List<ActivityGraphResponse.Edge> edges = createEdges();

            // When
            response.setEdges(edges);

            // Then
            assertThat(response.getEdges()).isEqualTo(edges);
        }

        @Test
        @DisplayName("多次设置nodes应该正确更新")
        void shouldUpdateCorrectly_WhenSettingNodesMultipleTimes() {
            // Given
            List<ActivityGraphResponse.Node> nodes1 = createNodes();
            response.setNodes(nodes1);
            assertThat(response.getNodes()).isEqualTo(nodes1);

            // When
            List<ActivityGraphResponse.Node> nodes2 = Collections.emptyList();
            response.setNodes(nodes2);

            // Then
            assertThat(response.getNodes()).isEqualTo(nodes2);
        }

        @Test
        @DisplayName("多次设置edges应该正确更新")
        void shouldUpdateCorrectly_WhenSettingEdgesMultipleTimes() {
            // Given
            List<ActivityGraphResponse.Edge> edges1 = createEdges();
            response.setEdges(edges1);
            assertThat(response.getEdges()).isEqualTo(edges1);

            // When
            List<ActivityGraphResponse.Edge> edges2 = Collections.emptyList();
            response.setEdges(edges2);

            // Then
            assertThat(response.getEdges()).isEqualTo(edges2);
        }

        @Test
        @DisplayName("设置null值应该正确处理")
        void shouldHandleNullValues_WhenSettingFields() {
            // Given
            response.setNodes(createNodes());
            response.setEdges(createEdges());

            // When
            response.setNodes(null);
            response.setEdges(null);

            // Then
            assertThat(response.getNodes()).isNull();
            assertThat(response.getEdges()).isNull();
        }
    }

    @Nested
    @DisplayName("Node内部类测试")
    class NodeTests {

        @Test
        @DisplayName("Node构造函数应该正确设置所有字段")
        void shouldSetAllFieldsCorrectly_WhenUsingNodeConstructor() {
            // Given
            String id = "node-1";
            String label = "用户A";

            // When
            ActivityGraphResponse.Node node = new ActivityGraphResponse.Node(id, label);

            // Then
            assertThat(node.getId()).isEqualTo(id);
            assertThat(node.getLabel()).isEqualTo(label);
        }

        @Test
        @DisplayName("Node getter和setter应该正常工作")
        void shouldWorkCorrectly_NodeGetterSetter() {
            // Given
            ActivityGraphResponse.Node node = new ActivityGraphResponse.Node("", "");

            // When
            node.setId("node-2");
            node.setLabel("用户B");

            // Then
            assertThat(node.getId()).isEqualTo("node-2");
            assertThat(node.getLabel()).isEqualTo("用户B");
        }

        @ParameterizedTest
        @NullAndEmptySource
        @ValueSource(strings = {"   ", "\t", "\n"})
        @DisplayName("Node应该处理各种空id值")
        void shouldHandleVariousEmptyNodeIds(String id) {
            // When
            ActivityGraphResponse.Node node = new ActivityGraphResponse.Node(id, "标签");

            // Then
            assertThat(node.getId()).isEqualTo(id);
        }

        @ParameterizedTest
        @NullAndEmptySource
        @ValueSource(strings = {"   ", "\t", "\n"})
        @DisplayName("Node应该处理各种空label值")
        void shouldHandleVariousEmptyNodeLabels(String label) {
            // When
            ActivityGraphResponse.Node node = new ActivityGraphResponse.Node("id", label);

            // Then
            assertThat(node.getLabel()).isEqualTo(label);
        }

        @Test
        @DisplayName("Node特殊字符应该正确处理")
        void shouldHandleSpecialCharacters_WhenUsingNode() {
            // Given
            String specialId = "node-🔑-测试@123";
            String specialLabel = "用户🎉包含中文!@#$%^&*()";

            // When
            ActivityGraphResponse.Node node = new ActivityGraphResponse.Node(specialId, specialLabel);

            // Then
            assertThat(node.getId()).isEqualTo(specialId);
            assertThat(node.getLabel()).isEqualTo(specialLabel);
        }

        @Test
        @DisplayName("Node多次设置应该正确更新")
        void shouldUpdateCorrectly_WhenSettingNodeMultipleTimes() {
            // Given
            ActivityGraphResponse.Node node = new ActivityGraphResponse.Node("node-1", "初始标签");

            // When
            node.setId("node-2");
            node.setLabel("更新后的标签");

            // Then
            assertThat(node.getId()).isEqualTo("node-2");
            assertThat(node.getLabel()).isEqualTo("更新后的标签");
        }

        @Test
        @DisplayName("Node长字符串应该正确处理")
        void shouldHandleLongStrings_WhenUsingNode() {
            // Given
            StringBuilder longId = new StringBuilder();
            StringBuilder longLabel = new StringBuilder();
            for (int i = 0; i < 100; i++) {
                longId.append("node-").append(i).append("-");
                longLabel.append("标签").append(i);
            }

            // When
            ActivityGraphResponse.Node node = new ActivityGraphResponse.Node(longId.toString(), longLabel.toString());

            // Then
            assertThat(node.getId()).hasSizeGreaterThan(500);
            assertThat(node.getLabel()).hasSizeGreaterThan(300);
        }
    }

    @Nested
    @DisplayName("Edge内部类测试")
    class EdgeTests {

        @Test
        @DisplayName("Edge构造函数应该正确设置所有字段")
        void shouldSetAllFieldsCorrectly_WhenUsingEdgeConstructor() {
            // Given
            String from = "node-1";
            String to = "node-2";

            // When
            ActivityGraphResponse.Edge edge = new ActivityGraphResponse.Edge(from, to);

            // Then
            assertThat(edge.getFrom()).isEqualTo(from);
            assertThat(edge.getTo()).isEqualTo(to);
        }

        @Test
        @DisplayName("Edge getter和setter应该正常工作")
        void shouldWorkCorrectly_EdgeGetterSetter() {
            // Given
            ActivityGraphResponse.Edge edge = new ActivityGraphResponse.Edge("", "");

            // When
            edge.setFrom("node-a");
            edge.setTo("node-b");

            // Then
            assertThat(edge.getFrom()).isEqualTo("node-a");
            assertThat(edge.getTo()).isEqualTo("node-b");
        }

        @ParameterizedTest
        @NullAndEmptySource
        @ValueSource(strings = {"   ", "\t", "\n"})
        @DisplayName("Edge应该处理各种空from值")
        void shouldHandleVariousEmptyFromValues(String from) {
            // When
            ActivityGraphResponse.Edge edge = new ActivityGraphResponse.Edge(from, "to");

            // Then
            assertThat(edge.getFrom()).isEqualTo(from);
        }

        @ParameterizedTest
        @NullAndEmptySource
        @ValueSource(strings = {"   ", "\t", "\n"})
        @DisplayName("Edge应该处理各种空to值")
        void shouldHandleVariousEmptyToValues(String to) {
            // When
            ActivityGraphResponse.Edge edge = new ActivityGraphResponse.Edge("from", to);

            // Then
            assertThat(edge.getTo()).isEqualTo(to);
        }

        @Test
        @DisplayName("Edge特殊字符应该正确处理")
        void shouldHandleSpecialCharacters_WhenUsingEdge() {
            // Given
            String from = "node-🔑-测试";
            String to = "node-🎉-特殊!@#";

            // When
            ActivityGraphResponse.Edge edge = new ActivityGraphResponse.Edge(from, to);

            // Then
            assertThat(edge.getFrom()).isEqualTo(from);
            assertThat(edge.getTo()).isEqualTo(to);
        }

        @Test
        @DisplayName("Edge多次设置应该正确更新")
        void shouldUpdateCorrectly_WhenSettingEdgeMultipleTimes() {
            // Given
            ActivityGraphResponse.Edge edge = new ActivityGraphResponse.Edge("node-1", "node-2");

            // When
            edge.setFrom("node-3");
            edge.setTo("node-4");

            // Then
            assertThat(edge.getFrom()).isEqualTo("node-3");
            assertThat(edge.getTo()).isEqualTo("node-4");
        }

        @Test
        @DisplayName("Edge循环引用应该正确处理")
        void shouldHandleCircularReference_WhenUsingEdge() {
            // Given
            String nodeId = "node-circular";

            // When - 自环边
            ActivityGraphResponse.Edge selfLoop = new ActivityGraphResponse.Edge(nodeId, nodeId);

            // Then
            assertThat(selfLoop.getFrom()).isEqualTo(nodeId);
            assertThat(selfLoop.getTo()).isEqualTo(nodeId);
            assertThat(selfLoop.getFrom()).isEqualTo(selfLoop.getTo());
        }

        @Test
        @DisplayName("Edge长字符串应该正确处理")
        void shouldHandleLongStrings_WhenUsingEdge() {
            // Given
            StringBuilder longFrom = new StringBuilder();
            StringBuilder longTo = new StringBuilder();
            for (int i = 0; i < 100; i++) {
                longFrom.append("from-").append(i).append("-");
                longTo.append("to-").append(i).append("-");
            }

            // When
            ActivityGraphResponse.Edge edge = new ActivityGraphResponse.Edge(longFrom.toString(), longTo.toString());

            // Then
            assertThat(edge.getFrom()).hasSizeGreaterThan(500);
            assertThat(edge.getTo()).hasSizeGreaterThan(500);
        }
    }

    @Nested
    @DisplayName("JSON序列化测试")
    class JsonSerializationTests {

        @Test
        @DisplayName("完整对象应该正确序列化为JSON")
        void shouldSerializeCorrectly_CompleteObject() throws JsonProcessingException {
            // Given
            List<ActivityGraphResponse.Node> nodes = createNodes();
            List<ActivityGraphResponse.Edge> edges = createEdges();
            ActivityGraphResponse response = new ActivityGraphResponse(nodes, edges);

            // When
            String json = objectMapper.writeValueAsString(response);

            // Then
            assertThat(json).isNotNull();
            assertThat(json).contains("\"nodes\"");
            assertThat(json).contains("\"edges\"");
            assertThat(json).contains("\"id\":\"node-1\"");
            assertThat(json).contains("\"from\":\"node-1\"");
        }

        @Test
        @DisplayName("空列表应该正确序列化为JSON")
        void shouldSerializeCorrectly_WithEmptyLists() throws JsonProcessingException {
            // Given
            ActivityGraphResponse response = new ActivityGraphResponse(Collections.emptyList(), Collections.emptyList());

            // When
            String json = objectMapper.writeValueAsString(response);

            // Then
            assertThat(json).contains("\"nodes\":[]");
            assertThat(json).contains("\"edges\":[]");
        }

        @Test
        @DisplayName("null值应该正确序列化为JSON")
        void shouldSerializeCorrectly_WithNullValues() throws JsonProcessingException {
            // Given
            ActivityGraphResponse response = new ActivityGraphResponse(null, null);

            // When
            String json = objectMapper.writeValueAsString(response);

            // Then
            assertThat(json).isNotNull();
        }

        @Test
        @DisplayName("包含特殊字符应该正确序列化为JSON")
        void shouldSerializeCorrectly_WithSpecialCharacters() throws JsonProcessingException {
            // Given
            ActivityGraphResponse.Node node = new ActivityGraphResponse.Node("node-🔑", "用户🎉");
            ActivityGraphResponse.Edge edge = new ActivityGraphResponse.Edge("node-🔑", "node-🎉");
            ActivityGraphResponse response = new ActivityGraphResponse(List.of(node), List.of(edge));

            // When
            String json = objectMapper.writeValueAsString(response);

            // Then
            assertThat(json).contains("node-🔑");
            assertThat(json).contains("用户🎉");
        }

        @Test
        @DisplayName("单个Node应该正确序列化为JSON")
        void shouldSerializeCorrectly_SingleNode() throws JsonProcessingException {
            // Given
            ActivityGraphResponse.Node node = new ActivityGraphResponse.Node("node-1", "标签1");

            // When
            String json = objectMapper.writeValueAsString(node);

            // Then
            assertThat(json).contains("\"id\":\"node-1\"");
            assertThat(json).contains("\"label\":\"标签1\"");
        }

        @Test
        @DisplayName("单个Edge应该正确序列化为JSON")
        void shouldSerializeCorrectly_SingleEdge() throws JsonProcessingException {
            // Given
            ActivityGraphResponse.Edge edge = new ActivityGraphResponse.Edge("node-1", "node-2");

            // When
            String json = objectMapper.writeValueAsString(edge);

            // Then
            assertThat(json).contains("\"from\":\"node-1\"");
            assertThat(json).contains("\"to\":\"node-2\"");
        }
    }

    @Nested
    @DisplayName("边界条件测试")
    class BoundaryTests {

        @Test
        @DisplayName("极大节点列表应该正确处理")
        void shouldHandleLargeNodeList() {
            // Given
            List<ActivityGraphResponse.Node> largeNodes = new ArrayList<>();
            for (int i = 0; i < 1000; i++) {
                largeNodes.add(new ActivityGraphResponse.Node("node-" + i, "用户" + i));
            }

            // When
            ActivityGraphResponse response = new ActivityGraphResponse(largeNodes, Collections.emptyList());

            // Then
            assertThat(response.getNodes()).hasSize(1000);
        }

        @Test
        @DisplayName("极大边列表应该正确处理")
        void shouldHandleLargeEdgeList() {
            // Given
            List<ActivityGraphResponse.Edge> largeEdges = new ArrayList<>();
            for (int i = 0; i < 1000; i++) {
                largeEdges.add(new ActivityGraphResponse.Edge("node-" + i, "node-" + (i + 1)));
            }

            // When
            ActivityGraphResponse response = new ActivityGraphResponse(Collections.emptyList(), largeEdges);

            // Then
            assertThat(response.getEdges()).hasSize(1000);
        }

        @Test
        @DisplayName("包含null元素的节点列表应该正确处理")
        void shouldHandleNodeListWithNullElements() {
            // Given
            List<ActivityGraphResponse.Node> nodesWithNull = new ArrayList<>();
            nodesWithNull.add(new ActivityGraphResponse.Node("node-1", "用户1"));
            nodesWithNull.add(null);

            // When
            ActivityGraphResponse response = new ActivityGraphResponse(nodesWithNull, Collections.emptyList());

            // Then
            assertThat(response.getNodes()).hasSize(2);
            assertThat(response.getNodes().get(0)).isNotNull();
            assertThat(response.getNodes().get(1)).isNull();
        }

        @Test
        @DisplayName("包含null元素的边列表应该正确处理")
        void shouldHandleEdgeListWithNullElements() {
            // Given
            List<ActivityGraphResponse.Edge> edgesWithNull = new ArrayList<>();
            edgesWithNull.add(new ActivityGraphResponse.Edge("node-1", "node-2"));
            edgesWithNull.add(null);

            // When
            ActivityGraphResponse response = new ActivityGraphResponse(Collections.emptyList(), edgesWithNull);

            // Then
            assertThat(response.getEdges()).hasSize(2);
            assertThat(response.getEdges().get(0)).isNotNull();
            assertThat(response.getEdges().get(1)).isNull();
        }

        @Test
        @DisplayName("复杂图结构应该正确处理")
        void shouldHandleComplexGraphStructure() {
            // Given - 创建复杂图：星形结构
            List<ActivityGraphResponse.Node> nodes = new ArrayList<>();
            List<ActivityGraphResponse.Edge> edges = new ArrayList<>();

            // 中心节点
            nodes.add(new ActivityGraphResponse.Node("center", "中心"));

            // 周围节点和边
            for (int i = 0; i < 10; i++) {
                nodes.add(new ActivityGraphResponse.Node("node-" + i, "用户" + i));
                edges.add(new ActivityGraphResponse.Edge("center", "node-" + i));
            }

            // When
            ActivityGraphResponse response = new ActivityGraphResponse(nodes, edges);

            // Then
            assertThat(response.getNodes()).hasSize(11);
            assertThat(response.getEdges()).hasSize(10);
        }
    }

    @Nested
    @DisplayName("并发安全测试")
    class ConcurrencyTests {

        @Test
        @DisplayName("多线程并发操作应该是安全的")
        void shouldBeThreadSafe_ConcurrentOperations() throws InterruptedException {
            // Given
            int threadCount = 10;
            Thread[] threads = new Thread[threadCount];
            boolean[] results = new boolean[threadCount];

            // When
            for (int i = 0; i < threadCount; i++) {
                final int threadIndex = i;
                threads[i] = new Thread(() -> {
                    try {
                        List<ActivityGraphResponse.Node> nodes = List.of(
                            new ActivityGraphResponse.Node("node-" + threadIndex, "用户" + threadIndex)
                        );
                        List<ActivityGraphResponse.Edge> edges = List.of(
                            new ActivityGraphResponse.Edge("from-" + threadIndex, "to-" + threadIndex)
                        );
                        
                        ActivityGraphResponse response = new ActivityGraphResponse(nodes, edges);
                        
                        // 验证getter
                        assertThat(response.getNodes()).hasSize(1);
                        assertThat(response.getEdges()).hasSize(1);
                        
                        results[threadIndex] = true;
                    } catch (Exception e) {
                        results[threadIndex] = false;
                    }
                });
            }

            // 启动所有线程
            for (Thread thread : threads) {
                thread.start();
            }

            // 等待所有线程完成
            for (Thread thread : threads) {
                thread.join();
            }

            // Then
            for (int i = 0; i < threadCount; i++) {
                assertThat(results[i]).isTrue();
            }
        }
    }

    private List<ActivityGraphResponse.Node> createNodes() {
        List<ActivityGraphResponse.Node> nodes = new ArrayList<>();
        nodes.add(new ActivityGraphResponse.Node("node-1", "用户A"));
        nodes.add(new ActivityGraphResponse.Node("node-2", "用户B"));
        nodes.add(new ActivityGraphResponse.Node("node-3", "用户C"));
        return nodes;
    }

    private List<ActivityGraphResponse.Edge> createEdges() {
        List<ActivityGraphResponse.Edge> edges = new ArrayList<>();
        edges.add(new ActivityGraphResponse.Edge("node-1", "node-2"));
        edges.add(new ActivityGraphResponse.Edge("node-2", "node-3"));
        edges.add(new ActivityGraphResponse.Edge("node-3", "node-1"));
        return edges;
    }
}
