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 static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
 * CreateApiKeyResponse DTO测试
 */
@DisplayName("CreateApiKeyResponse DTO测试")
class CreateApiKeyResponseTest {

    private ObjectMapper objectMapper;

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

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

        @Test
        @DisplayName("全参数构造函数应该正确设置apiKey字段")
        void shouldSetApiKeyCorrectly_WhenUsingAllArgsConstructor() {
            // Given
            String apiKey = "test-api-key-12345";

            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);

            // Then
            assertThat(response.getApiKey()).isEqualTo(apiKey);
        }

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

            // Then
            assertThat(response.getApiKey()).isNull();
        }

        @Test
        @DisplayName("空字符串构造函数应该正确处理")
        void shouldHandleEmptyString_WhenUsingConstructor() {
            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse("");

            // Then
            assertThat(response.getApiKey()).isEmpty();
        }

        @Test
        @DisplayName("空白字符串构造函数应该正确处理")
        void shouldHandleWhitespace_WhenUsingConstructor() {
            // Given
            String whitespaceKey = "   ";

            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse(whitespaceKey);

            // Then
            assertThat(response.getApiKey()).isEqualTo(whitespaceKey);
        }

        @Test
        @DisplayName("长字符串构造函数应该正确处理")
        void shouldHandleLongString_WhenUsingConstructor() {
            // Given
            StringBuilder longKey = new StringBuilder();
            for (int i = 0; i < 1000; i++) {
                longKey.append("key").append(i);
            }
            String longApiKey = longKey.toString();

            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse(longApiKey);

            // Then
            assertThat(response.getApiKey()).isEqualTo(longApiKey);
            assertThat(response.getApiKey()).hasSizeGreaterThan(2000);
        }

        @Test
        @DisplayName("特殊字符apiKey构造函数应该正确处理")
        void shouldHandleSpecialCharacters_WhenUsingConstructor() {
            // Given
            String specialKey = "key-🔑-测试!@#$%^&*()_+-=[]{}|;':\",./<>?";

            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse(specialKey);

            // Then
            assertThat(response.getApiKey()).isEqualTo(specialKey);
        }

        @Test
        @DisplayName("包含换行符apiKey构造函数应该正确处理")
        void shouldHandleNewlines_WhenUsingConstructor() {
            // Given
            String keyWithNewlines = "line1\nline2\r\nline3\t";

            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse(keyWithNewlines);

            // Then
            assertThat(response.getApiKey()).isEqualTo(keyWithNewlines);
        }
    }

    @Nested
    @DisplayName("Getter测试")
    class GetterTests {

        @Test
        @DisplayName("getApiKey应该返回正确的值")
        void shouldReturnCorrectValue_WhenUsingGetter() {
            // Given
            String apiKey = "my-secret-api-key";
            CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);

            // When
            String result = response.getApiKey();

            // Then
            assertThat(result).isEqualTo(apiKey);
        }

        @Test
        @DisplayName("getApiKey应该返回null当值为null")
        void shouldReturnNull_WhenValueIsNull() {
            // Given
            CreateApiKeyResponse response = new CreateApiKeyResponse(null);

            // When
            String result = response.getApiKey();

            // Then
            assertThat(result).isNull();
        }

        @Test
        @DisplayName("getApiKey应该返回空字符串当值为空")
        void shouldReturnEmptyString_WhenValueIsEmpty() {
            // Given
            CreateApiKeyResponse response = new CreateApiKeyResponse("");

            // When
            String result = response.getApiKey();

            // Then
            assertThat(result).isEmpty();
        }
    }

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

        @ParameterizedTest
        @NullAndEmptySource
        @ValueSource(strings = {"   ", "\t", "\n", "\r"})
        @DisplayName("边界值apiKey应该正确处理")
        void shouldHandleBoundaryValues(String apiKey) {
            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);

            // Then
            assertThat(response.getApiKey()).isEqualTo(apiKey);
        }

        @ParameterizedTest
        @ValueSource(strings = {
            "a",  // 单字符
            "AB", // 双字符
            "0123456789", // 数字
            "abcdefghijklmnopqrstuvwxyz", // 小写字母
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ", // 大写字母
            "key-with-dashes", // 带横线
            "key_with_underscores", // 带下划线
            "key.with.dots", // 带点
            "key:with:colons", // 带冒号
            "key/with/slashes" // 带斜杠
        })
        @DisplayName("各种格式apiKey应该正确处理")
        void shouldHandleVariousFormats(String apiKey) {
            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);

            // Then
            assertThat(response.getApiKey()).isEqualTo(apiKey);
        }

        @Test
        @DisplayName("Unicode字符apiKey应该正确处理")
        void shouldHandleUnicodeCharacters() {
            // Given
            String[] unicodeKeys = {
                "密钥-中文测试",
                "ключ-русский",
                "キー-日本語",
                "🔑-emoji-test",
                "مفتاح-عربي"
            };

            for (String key : unicodeKeys) {
                // When
                CreateApiKeyResponse response = new CreateApiKeyResponse(key);

                // Then
                assertThat(response.getApiKey()).isEqualTo(key);
            }
        }

        @Test
        @DisplayName("极大长度apiKey应该正确处理")
        void shouldHandleExtremelyLongKey() {
            // Given
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 10000; i++) {
                sb.append("A");
            }
            String extremelyLongKey = sb.toString();

            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse(extremelyLongKey);

            // Then
            assertThat(response.getApiKey()).hasSize(10000);
            assertThat(response.getApiKey()).isEqualTo(extremelyLongKey);
        }

        @Test
        @DisplayName("JSON特殊字符apiKey应该正确处理")
        void shouldHandleJsonSpecialCharacters() {
            // Given
            String jsonSpecialKey = "key{with}[brackets]\"quotes\"'apostrophe'";

            // When
            CreateApiKeyResponse response = new CreateApiKeyResponse(jsonSpecialKey);

            // Then
            assertThat(response.getApiKey()).isEqualTo(jsonSpecialKey);
        }
    }

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

        @Test
        @DisplayName("完整对象应该正确序列化为JSON")
        void shouldSerializeCorrectly_CompleteObject() throws JsonProcessingException {
            // Given
            String apiKey = "test-api-key-12345";
            CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);

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

            // Then
            assertThat(json).isNotNull();
            assertThat(json).contains("\"apiKey\":\"test-api-key-12345\"");
        }

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

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

            // Then
            assertThat(json).isNotNull();
            assertThat(json).contains("\"apiKey\":null");
        }

        @Test
        @DisplayName("空字符串应该正确序列化为JSON")
        void shouldSerializeCorrectly_WithEmptyString() throws JsonProcessingException {
            // Given
            CreateApiKeyResponse response = new CreateApiKeyResponse("");

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

            // Then
            assertThat(json).contains("\"apiKey\":\"\"");
        }

        @Test
        @DisplayName("特殊字符应该正确序列化为JSON")
        void shouldSerializeCorrectly_WithSpecialCharacters() throws JsonProcessingException {
            // Given
            String specialKey = "key-🔑-测试";
            CreateApiKeyResponse response = new CreateApiKeyResponse(specialKey);

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

            // Then
            assertThat(json).isNotNull();
            assertThat(json).contains("apiKey");
        }

        @Test
        @DisplayName("JSON转义字符应该正确序列化")
        void shouldSerializeCorrectly_WithJsonEscapes() throws JsonProcessingException {
            // Given
            String keyWithEscapes = "line1\nline2\t\"quoted\"";
            CreateApiKeyResponse response = new CreateApiKeyResponse(keyWithEscapes);

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

            // Then
            assertThat(json).isNotNull();
            assertThat(json).contains("apiKey");
        }
    }

    @Nested
    @DisplayName("对象行为测试")
    class ObjectBehaviorTests {

        @Test
        @DisplayName("两个相同apiKey的响应应该相等")
        void shouldBeEqual_WhenSameApiKey() {
            // Given
            CreateApiKeyResponse response1 = new CreateApiKeyResponse("same-key");
            CreateApiKeyResponse response2 = new CreateApiKeyResponse("same-key");

            // Then
            assertThat(response1.getApiKey()).isEqualTo(response2.getApiKey());
        }

        @Test
        @DisplayName("两个不同apiKey的响应应该不相等")
        void shouldNotBeEqual_WhenDifferentApiKey() {
            // Given
            CreateApiKeyResponse response1 = new CreateApiKeyResponse("key-1");
            CreateApiKeyResponse response2 = new CreateApiKeyResponse("key-2");

            // Then
            assertThat(response1.getApiKey()).isNotEqualTo(response2.getApiKey());
        }

        @Test
        @DisplayName("多次调用getter应该返回相同值")
        void shouldReturnSameValue_WhenCallingGetterMultipleTimes() {
            // Given
            String apiKey = "consistent-key";
            CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);

            // When & Then
            assertThat(response.getApiKey()).isEqualTo(apiKey);
            assertThat(response.getApiKey()).isEqualTo(apiKey);
            assertThat(response.getApiKey()).isEqualTo(apiKey);
        }
    }

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

        @Test
        @DisplayName("多线程并发读取应该是安全的")
        void shouldBeThreadSafe_ConcurrentReads() throws InterruptedException {
            // Given
            String apiKey = "concurrent-key";
            CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);
            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 {
                        for (int j = 0; j < 100; j++) {
                            String value = response.getApiKey();
                            if (!apiKey.equals(value)) {
                                results[threadIndex] = false;
                                return;
                            }
                        }
                        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();
            }
        }
    }
}
