package com.mosquito.project.dto;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
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.ValueSource;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.NullSource;

import java.util.Set;

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

/**
 * CreateApiKeyRequest DTO测试
 */
@DisplayName("CreateApiKeyRequest DTO测试")
class CreateApiKeyRequestTest {

    private Validator validator;
    private CreateApiKeyRequest request;
    private ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
        request = new CreateApiKeyRequest();
        objectMapper = new ObjectMapper();
    }

    @Nested
    @DisplayName("验证测试")
    class ValidationTests {

        @Test
        @DisplayName("有效的请求应该通过验证")
        void shouldPassValidation_WhenValidRequest() {
            // Given
            request.setActivityId(123L);
            request.setName("测试API密钥");

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertTrue(violations.isEmpty(), "有效的请求应该通过验证");
        }

        @ParameterizedTest
        @NullSource
        @DisplayName("null活动ID应该失败验证")
        void shouldFailValidation_WhenActivityIdIsNull(Long activityId) {
            // Given
            request.setActivityId(activityId);
            request.setName("测试名称");

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertFalse(violations.isEmpty(), "null活动ID应该验证失败");
            assertEquals(1, violations.size());
            
            ConstraintViolation<CreateApiKeyRequest> violation = violations.iterator().next();
            assertEquals("activityId", violation.getPropertyPath().toString());
            assertEquals("活动ID不能为空", violation.getMessage());
        }

        @ParameterizedTest
        @NullAndEmptySource
        @ValueSource(strings = {"   ", "\t", "\n"})
        @DisplayName("空名称应该失败验证")
        void shouldFailValidation_WhenNameIsInvalid(String name) {
            // Given
            request.setActivityId(123L);
            request.setName(name);

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertFalse(violations.isEmpty(), "空名称应该验证失败");
            assertEquals(1, violations.size());
            
            ConstraintViolation<CreateApiKeyRequest> violation = violations.iterator().next();
            assertEquals("name", violation.getPropertyPath().toString());
            assertEquals("密钥名称不能为空", violation.getMessage());
        }

        @Test
        @DisplayName("所有字段为空应该返回多个验证错误")
        void shouldReturnMultipleViolations_WhenAllFieldsNull() {
            // Given
            request.setActivityId(null);
            request.setName(null);

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertEquals(2, violations.size());
            
            boolean foundActivityIdViolation = false;
            boolean foundNameViolation = false;
            
            for (ConstraintViolation<CreateApiKeyRequest> violation : violations) {
                String property = violation.getPropertyPath().toString();
                if ("activityId".equals(property)) {
                    foundActivityIdViolation = true;
                    assertEquals("活动ID不能为空", violation.getMessage());
                } else if ("name".equals(property)) {
                    foundNameViolation = true;
                    assertEquals("密钥名称不能为空", violation.getMessage());
                }
            }
            
            assertTrue(foundActivityIdViolation);
            assertTrue(foundNameViolation);
        }

        @ParameterizedTest
        @CsvSource({
            "1, 密钥1",
            "999999999, 非常长的名称用于测试边界条件是否能够正确处理各种不同长度的输入",
            "0, 最小ID",
            "-1, 负数ID"
        })
        @DisplayName("各种有效活动ID应该通过验证")
        void shouldPassValidation_WithVariousValidActivityIds(Long activityId, String name) {
            // Given
            request.setActivityId(activityId);
            request.setName(name);

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertTrue(violations.isEmpty(), "活动ID " + activityId + " 应该通过验证");
        }
    }

    @Nested
    @DisplayName("功能测试")
    class FunctionalTests {

        @Test
        @DisplayName("getter和setter应该正常工作")
        void shouldWorkCorrectly_GetterAndSetter() {
            // Given
            Long testActivityId = 12345L;
            String testName = "测试API密钥名称";

            // When
            request.setActivityId(testActivityId);
            request.setName(testName);

            // Then
            assertEquals(testActivityId, request.getActivityId());
            assertEquals(testName, request.getName());
        }

        @Test
        @DisplayName("多次设置应该正确更新")
        void shouldUpdateCorrectly_WhenSetMultipleTimes() {
            // Given
            request.setActivityId(100L);
            request.setName("初始名称");
            
            // When
            request.setActivityId(200L);
            request.setName("更新后的名称");
            
            // Then
            assertEquals(200L, request.getActivityId());
            assertEquals("更新后的名称", request.getName());
            assertNotEquals(100L, request.getActivityId());
            assertNotEquals("初始名称", request.getName());
        }

        @Test
        @DisplayName("设置null应该正确处理")
        void shouldHandleNullValues() {
            // Given
            request.setActivityId(123L);
            request.setName("测试名称");
            assertNotNull(request.getActivityId());
            assertNotNull(request.getName());

            // When
            request.setActivityId(null);
            request.setName(null);

            // Then
            assertNull(request.getActivityId());
            assertNull(request.getName());
        }

        @Test
        @DisplayName("对象相等性测试")
        void testObjectEquality() {
            // Given
            CreateApiKeyRequest request1 = new CreateApiKeyRequest();
            CreateApiKeyRequest request2 = new CreateApiKeyRequest();
            
            request1.setActivityId(123L);
            request1.setName("测试");
            request2.setActivityId(123L);
            request2.setName("测试");

            // When & Then
            assertEquals(request1.getActivityId(), request2.getActivityId());
            assertEquals(request1.getName(), request2.getName());
            
            // 测试不同对象
            request2.setActivityId(456L);
            assertNotEquals(request1.getActivityId(), request2.getActivityId());
        }
    }

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

        @Test
        @DisplayName("完整对象应该正确序列化为JSON")
        void shouldSerializeCorrectly_CompleteObject() throws JsonProcessingException {
            // Given
            request.setActivityId(123L);
            request.setName("测试API密钥");

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

            // Then
            assertNotNull(json);
            assertTrue(json.contains("\"activityId\":123"));
            assertTrue(json.contains("\"name\":\"测试API密钥\""));
        }

        @Test
        @DisplayName("null字段应该正确序列化")
        void shouldSerializeCorrectly_WithNullFields() throws JsonProcessingException {
            // Given
            request.setActivityId(null);
            request.setName(null);

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

            // Then
            assertNotNull(json);
            // null字段的处理取决于Jackson配置
            assertTrue(json.contains("activityId"));
            assertTrue(json.contains("name"));
        }

        @Test
        @DisplayName("空字符串应该正确序列化")
        void shouldSerializeCorrectly_WithEmptyString() throws JsonProcessingException {
            // Given
            request.setActivityId(123L);
            request.setName("");

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

            // Then
            assertNotNull(json);
            assertTrue(json.contains("\"activityId\":123"));
            assertTrue(json.contains("\"name\":\"\""));
        }

        @Test
        @DisplayName("特殊字符应该正确序列化")
        void shouldSerializeCorrectly_WithSpecialCharacters() throws JsonProcessingException {
            // Given
            String specialName = "API密钥包含\"引号'和\\反斜杠\n换行\t制表符";
            request.setActivityId(456L);
            request.setName(specialName);

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

            // Then
            assertNotNull(json);
            assertTrue(json.contains("\"activityId\":456"));
            // 特殊字符应该被正确转义
            assertTrue(json.contains("name"));
        }
    }

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

        @Test
        @DisplayName("完整JSON应该正确反序列化")
        void shouldDeserializeCorrectly_CompleteJson() throws JsonProcessingException {
            // Given
            String json = "{\"activityId\":789,\"name\":\"反序列化测试\"}";

            // When
            CreateApiKeyRequest deserialized = objectMapper.readValue(json, CreateApiKeyRequest.class);

            // Then
            assertEquals(789L, deserialized.getActivityId());
            assertEquals("反序列化测试", deserialized.getName());
        }

        @Test
        @DisplayName("部分字段JSON应该正确反序列化")
        void shouldDeserializeCorrectly_PartialFieldsJson() throws JsonProcessingException {
            // Given
            String json = "{\"activityId\":999}";

            // When
            CreateApiKeyRequest deserialized = objectMapper.readValue(json, CreateApiKeyRequest.class);

            // Then
            assertEquals(999L, deserialized.getActivityId());
            assertNull(deserialized.getName());
        }

        @Test
        @DisplayName("空对象JSON应该正确反序列化")
        void shouldDeserializeCorrectly_EmptyObjectJson() throws JsonProcessingException {
            // Given
            String json = "{}";

            // When
            CreateApiKeyRequest deserialized = objectMapper.readValue(json, CreateApiKeyRequest.class);

            // Then
            assertNull(deserialized.getActivityId());
            assertNull(deserialized.getName());
        }

        @Test
        @DisplayName("null值JSON应该正确反序列化")
        void shouldDeserializeCorrectly_NullValuesJson() throws JsonProcessingException {
            // Given
            String json = "{\"activityId\":null,\"name\":null}";

            // When
            CreateApiKeyRequest deserialized = objectMapper.readValue(json, CreateApiKeyRequest.class);

            // Then
            assertNull(deserialized.getActivityId());
            assertNull(deserialized.getName());
        }

        @Test
        @DisplayName("JSON格式错误应该抛出异常")
        void shouldThrowException_WhenJsonIsMalformed() {
            // Given
            String malformedJson = "{\"activityId\":123,\"name\":\"测试\""; // 缺少闭合括号

            // When & Then
            assertThrows(JsonProcessingException.class, () -> {
                objectMapper.readValue(malformedJson, CreateApiKeyRequest.class);
            });
        }
    }

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

        @Test
        @DisplayName("极大活动ID应该正确处理")
        void shouldHandleLargeActivityId() {
            // Given
            Long maxActivityId = Long.MAX_VALUE;
            request.setActivityId(maxActivityId);
            request.setName("最大ID测试");

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertTrue(violations.isEmpty(), "最大活动ID应该通过验证");
            assertEquals(maxActivityId, request.getActivityId());
        }

        @Test
        @DisplayName("极小活动ID应该正确处理")
        void shouldHandleMinActivityId() {
            // Given
            Long minActivityId = Long.MIN_VALUE;
            request.setActivityId(minActivityId);
            request.setName("最小ID测试");

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertTrue(violations.isEmpty(), "最小活动ID应该通过验证");
            assertEquals(minActivityId, request.getActivityId());
        }

        @Test
        @DisplayName("超长名称应该正确处理")
        void shouldHandleLongName() {
            // Given
            StringBuilder longName = new StringBuilder();
            for (int i = 0; i < 1000; i++) {
                longName.append("很长的名称");
            }
            String veryLongName = longName.toString();
            request.setActivityId(123L);
            request.setName(veryLongName);

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertTrue(violations.isEmpty(), "超长名称应该通过验证");
            assertEquals(veryLongName, request.getName());
        }

        @Test
        @DisplayName("名称包含特殊字符应该正确处理")
        void shouldHandleSpecialCharactersInName() {
            // Given
            String specialName = "API密钥🔑包含中文、emoji、符号!@#$%^&*()_+-=[]{}|;':\",./<>?";
            request.setActivityId(123L);
            request.setName(specialName);

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertTrue(violations.isEmpty(), "包含特殊字符的名称应该通过验证");
            assertEquals(specialName, request.getName());
        }

        @Test
        @DisplayName("名称包含空白字符应该正确处理")
        void shouldHandleWhitespaceCharactersInName() {
            // Given
            String whitespaceName = "  包含   多个  空格  \t和\n换行  的名称  ";
            request.setActivityId(123L);
            request.setName(whitespaceName);

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertTrue(violations.isEmpty(), "包含空白字符的名称应该通过验证");
            assertEquals(whitespaceName, request.getName());
        }

        @ParameterizedTest
        @ValueSource(strings = {
            "a", // 单字符
            "API Key", // 英文
            "API密钥", // 中文
            "API ключ", // 俄文
            "APIキー", // 日文
            "مفتاح API", // 阿拉伯文
            "🔑🔐🛡️" // 只有emoji
        })
        @DisplayName("各种语言的名称应该正确处理")
        void shouldHandleVariousLanguages(String name) {
            // Given
            request.setActivityId(123L);
            request.setName(name);

            // When
            Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);

            // Then
            assertTrue(violations.isEmpty(), "各种语言的名称应该通过验证");
            assertEquals(name, request.getName());
        }
    }

    @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 {
                        CreateApiKeyRequest localRequest = new CreateApiKeyRequest();
                        localRequest.setActivityId((long) threadIndex);
                        localRequest.setName("线程" + threadIndex);
                        
                        // 验证getter/setter
                        assertEquals((long) threadIndex, localRequest.getActivityId());
                        assertEquals("线程" + threadIndex, localRequest.getName());
                        
                        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++) {
                assertTrue(results[i], "线程 " + i + " 的操作应该成功");
            }
        }
    }
}
