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;

/**
 * RevealApiKeyResponse DTO测试
 */
@DisplayName("RevealApiKeyResponse DTO测试")
class RevealApiKeyResponseTest {

    private ObjectMapper objectMapper;

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

    @Nested
    @DisplayName("无参构造函数测试")
    class NoArgsConstructorTests {

        @Test
        @DisplayName("无参构造函数应该创建空对象")
        void shouldCreateEmptyObject_WhenUsingNoArgsConstructor() {
            // When
            RevealApiKeyResponse response = new RevealApiKeyResponse();

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

        @Test
        @DisplayName("无参构造函数创建的对象应该允许setter操作")
        void shouldAllowSetterOperations_WhenUsingNoArgsConstructor() {
            // Given
            RevealApiKeyResponse response = new RevealApiKeyResponse();

            // When
            response.setApiKey("test-key");
            response.setMessage("test-message");

            // Then
            assertThat(response.getApiKey()).isEqualTo("test-key");
            assertThat(response.getMessage()).isEqualTo("test-message");
        }
    }

    @Nested
    @DisplayName("全参构造函数测试")
    class AllArgsConstructorTests {

        @Test
        @DisplayName("全参构造函数应该正确设置所有字段")
        void shouldSetAllFieldsCorrectly_WhenUsingAllArgsConstructor() {
            // Given
            String apiKey = "revealed-api-key-123";
            String message = "API密钥已揭示";

            // When
            RevealApiKeyResponse response = new RevealApiKeyResponse(apiKey, message);

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

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

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

        @Test
        @DisplayName("部分null值构造函数应该正确处理")
        void shouldHandlePartialNullValues_WhenUsingConstructor() {
            // Given
            String apiKey = "test-key";

            // When
            RevealApiKeyResponse response = new RevealApiKeyResponse(apiKey, null);

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

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

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

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

        private RevealApiKeyResponse response;

        @BeforeEach
        void setUp() {
            response = new RevealApiKeyResponse();
        }

        @Test
        @DisplayName("apiKey字段的getter和setter应该正常工作")
        void shouldWorkCorrectly_ApiKeyGetterSetter() {
            // Given
            String apiKey = "my-api-key";

            // When
            response.setApiKey(apiKey);

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

        @Test
        @DisplayName("message字段的getter和setter应该正常工作")
        void shouldWorkCorrectly_MessageGetterSetter() {
            // Given
            String message = "操作成功消息";

            // When
            response.setMessage(message);

            // Then
            assertThat(response.getMessage()).isEqualTo(message);
        }

        @Test
        @DisplayName("多次设置apiKey应该正确更新")
        void shouldUpdateCorrectly_WhenSettingApiKeyMultipleTimes() {
            // Given
            response.setApiKey("key-1");
            assertThat(response.getApiKey()).isEqualTo("key-1");

            // When
            response.setApiKey("key-2");

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

        @Test
        @DisplayName("多次设置message应该正确更新")
        void shouldUpdateCorrectly_WhenSettingMessageMultipleTimes() {
            // Given
            response.setMessage("message-1");
            assertThat(response.getMessage()).isEqualTo("message-1");

            // When
            response.setMessage("message-2");

            // Then
            assertThat(response.getMessage()).isEqualTo("message-2");
        }

        @Test
        @DisplayName("设置null值应该正确处理")
        void shouldHandleNullValues_WhenSettingFields() {
            // Given
            response.setApiKey("test-key");
            response.setMessage("test-message");
            assertThat(response.getApiKey()).isNotNull();
            assertThat(response.getMessage()).isNotNull();

            // When
            response.setApiKey(null);
            response.setMessage(null);

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

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

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

            // When
            response.setApiKey(apiKey);

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

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

            // When
            response.setMessage(message);

            // Then
            assertThat(response.getMessage()).isEqualTo(message);
        }

        @Test
        @DisplayName("长字符串apiKey应该正确处理")
        void shouldHandleLongApiKey() {
            // Given
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 1000; i++) {
                sb.append("key").append(i);
            }
            String longApiKey = sb.toString();
            RevealApiKeyResponse response = new RevealApiKeyResponse();

            // When
            response.setApiKey(longApiKey);

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

        @Test
        @DisplayName("长字符串message应该正确处理")
        void shouldHandleLongMessage() {
            // Given
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 1000; i++) {
                sb.append("message").append(i).append(" ");
            }
            String longMessage = sb.toString();
            RevealApiKeyResponse response = new RevealApiKeyResponse();

            // When
            response.setMessage(longMessage);

            // Then
            assertThat(response.getMessage()).hasSizeGreaterThan(7000);
        }

        @Test
        @DisplayName("特殊字符字段应该正确处理")
        void shouldHandleSpecialCharacters() {
            // Given
            RevealApiKeyResponse response = new RevealApiKeyResponse();
            String specialApiKey = "key-🔑-测试!@#$%^&*()";
            String specialMessage = "消息🎉包含特殊字符<>?\"'";

            // When
            response.setApiKey(specialApiKey);
            response.setMessage(specialMessage);

            // Then
            assertThat(response.getApiKey()).isEqualTo(specialApiKey);
            assertThat(response.getMessage()).isEqualTo(specialMessage);
        }

        @Test
        @DisplayName("Unicode字符字段应该正确处理")
        void shouldHandleUnicodeCharacters() {
            // Given
            RevealApiKeyResponse response = new RevealApiKeyResponse();

            // When & Then
            response.setApiKey("密钥-中文");
            assertThat(response.getApiKey()).isEqualTo("密钥-中文");

            response.setApiKey("ключ-русский");
            assertThat(response.getApiKey()).isEqualTo("ключ-русский");

            response.setMessage("🔑-emoji-test");
            assertThat(response.getMessage()).isEqualTo("🔑-emoji-test");
        }

        @Test
        @DisplayName("包含换行符字段应该正确处理")
        void shouldHandleNewlines() {
            // Given
            RevealApiKeyResponse response = new RevealApiKeyResponse();
            String keyWithNewlines = "key\nwith\nnewlines";
            String messageWithNewlines = "message\r\nwith\r\nnewlines";

            // When
            response.setApiKey(keyWithNewlines);
            response.setMessage(messageWithNewlines);

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

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

        @Test
        @DisplayName("完整对象应该正确序列化为JSON")
        void shouldSerializeCorrectly_CompleteObject() throws JsonProcessingException {
            // Given
            RevealApiKeyResponse response = new RevealApiKeyResponse("revealed-key-123", "密钥已揭示");

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

            // Then
            assertThat(json).isNotNull();
            assertThat(json).contains("\"apiKey\":\"revealed-key-123\"");
            assertThat(json).contains("\"message\":\"密钥已揭示\"");
        }

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

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

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

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

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

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

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

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

            // Then
            assertThat(json).isNotNull();
            // 验证反序列化后值相同
            RevealApiKeyResponse deserialized = objectMapper.readValue(json, RevealApiKeyResponse.class);
            assertThat(deserialized.getApiKey()).isEqualTo("key-🔑-测试");
            assertThat(deserialized.getMessage()).isEqualTo("消息🎉");
        }

        @Test
        @DisplayName("部分字段应该正确序列化为JSON")
        void shouldSerializeCorrectly_WithPartialFields() throws JsonProcessingException {
            // Given
            RevealApiKeyResponse response = new RevealApiKeyResponse();
            response.setApiKey("only-api-key");

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

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

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

        @Test
        @DisplayName("完整JSON应该正确反序列化")
        void shouldDeserializeCorrectly_CompleteJson() throws JsonProcessingException {
            // Given
            String json = "{\"apiKey\":\"revealed-key\",\"message\":\"密钥揭示成功\"}";

            // When
            RevealApiKeyResponse response = objectMapper.readValue(json, RevealApiKeyResponse.class);

            // Then
            assertThat(response.getApiKey()).isEqualTo("revealed-key");
            assertThat(response.getMessage()).isEqualTo("密钥揭示成功");
        }

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

            // When
            RevealApiKeyResponse response = objectMapper.readValue(json, RevealApiKeyResponse.class);

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

        @Test
        @DisplayName("空字符串JSON应该正确反序列化")
        void shouldDeserializeCorrectly_WithEmptyStrings() throws JsonProcessingException {
            // Given
            String json = "{\"apiKey\":\"\",\"message\":\"\"}";

            // When
            RevealApiKeyResponse response = objectMapper.readValue(json, RevealApiKeyResponse.class);

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

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

            // When
            RevealApiKeyResponse response = objectMapper.readValue(json, RevealApiKeyResponse.class);

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

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

            // When
            RevealApiKeyResponse response = objectMapper.readValue(json, RevealApiKeyResponse.class);

            // Then
            assertThat(response.getApiKey()).isEqualTo("only-key");
            assertThat(response.getMessage()).isNull();
        }

        @Test
        @DisplayName("特殊字符JSON应该正确反序列化")
        void shouldDeserializeCorrectly_WithSpecialCharacters() throws JsonProcessingException {
            // Given
            String json = "{\"apiKey\":\"key-🔑\",\"message\":\"消息🎉\"}";

            // When
            RevealApiKeyResponse response = objectMapper.readValue(json, RevealApiKeyResponse.class);

            // Then
            assertThat(response.getApiKey()).isEqualTo("key-🔑");
            assertThat(response.getMessage()).isEqualTo("消息🎉");
        }

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

            // When & Then
            assertThatThrownBy(() -> objectMapper.readValue(malformedJson, RevealApiKeyResponse.class))
                .isInstanceOf(JsonProcessingException.class);
        }
    }

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

        @Test
        @DisplayName("构造函数和setter组合使用应该正常工作")
        void shouldWorkCorrectly_WhenCombiningConstructorAndSetter() {
            // Given
            RevealApiKeyResponse response = new RevealApiKeyResponse("initial-key", "initial-message");

            // When
            response.setApiKey("updated-key");
            response.setMessage("updated-message");

            // Then
            assertThat(response.getApiKey()).isEqualTo("updated-key");
            assertThat(response.getMessage()).isEqualTo("updated-message");
        }

        @Test
        @DisplayName("对象状态应该在setter调用后保持正确")
        void shouldMaintainCorrectState_AfterSetterCalls() {
            // Given
            RevealApiKeyResponse response = new RevealApiKeyResponse();

            // When - 多次设置不同值
            response.setApiKey("key-1");
            assertThat(response.getApiKey()).isEqualTo("key-1");

            response.setApiKey("key-2");
            assertThat(response.getApiKey()).isEqualTo("key-2");

            response.setApiKey(null);
            assertThat(response.getApiKey()).isNull();

            response.setApiKey("key-3");

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

    @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 {
                        RevealApiKeyResponse response = new RevealApiKeyResponse(
                            "key-" + threadIndex,
                            "message-" + threadIndex
                        );
                        
                        // 验证getter
                        assertThat(response.getApiKey()).isEqualTo("key-" + threadIndex);
                        assertThat(response.getMessage()).isEqualTo("message-" + threadIndex);
                        
                        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();
            }
        }
    }
}
