package com.mosquito.project.dto;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.NotBlank;

import java.util.Set;

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

/**
 * DTO验证测试 - 提升DTO模块覆盖率
 */
@ExtendWith(MockitoExtension.class)
class DtoValidationTest {

    private Validator validator;

    @BeforeEach
    void setUp() {
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        factoryBean.afterPropertiesSet();
        validator = factoryBean.getValidator();
    }

    @Test
    @DisplayName("CreateApiKeyRequest - 验证有效的请求")
    void testCreateApiKeyRequest_Valid() {
        // Setup
        CreateApiKeyRequest request = new CreateApiKeyRequest();
        request.setActivityId(1L);
        request.setName("测试密钥");

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

        // Verify
        assertTrue(violations.isEmpty());
    }

    @Test
    @DisplayName("CreateApiKeyRequest - activityId为空")
    void testCreateApiKeyRequest_NullActivityId() {
        // Setup
        CreateApiKeyRequest request = new CreateApiKeyRequest();
        request.setActivityId(null);
        request.setName("测试密钥");

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

        // Verify
        assertEquals(1, violations.size());
        ConstraintViolation<CreateApiKeyRequest> violation = violations.iterator().next();
        assertEquals("activityId", violation.getPropertyPath().toString());
        assertEquals("活动ID不能为空", violation.getMessage());
    }

    @Test
    @DisplayName("CreateApiKeyRequest - name为空")
    void testCreateApiKeyRequest_NullName() {
        // Setup
        CreateApiKeyRequest request = new CreateApiKeyRequest();
        request.setActivityId(1L);
        request.setName(null);

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

        // Verify
        assertEquals(1, violations.size());
        ConstraintViolation<CreateApiKeyRequest> violation = violations.iterator().next();
        assertEquals("name", violation.getPropertyPath().toString());
        assertEquals("密钥名称不能为空", violation.getMessage());
    }

    @Test
    @DisplayName("CreateApiKeyRequest - name为空字符串")
    void testCreateApiKeyRequest_EmptyName() {
        // Setup
        CreateApiKeyRequest request = new CreateApiKeyRequest();
        request.setActivityId(1L);
        request.setName("");

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

        // Verify
        assertEquals(1, violations.size());
        ConstraintViolation<CreateApiKeyRequest> violation = violations.iterator().next();
        assertEquals("name", violation.getPropertyPath().toString());
        assertEquals("密钥名称不能为空", violation.getMessage());
    }

    @Test
    @DisplayName("CreateApiKeyRequest - name为空白字符串")
    void testCreateApiKeyRequest_BlankName() {
        // Setup
        CreateApiKeyRequest request = new CreateApiKeyRequest();
        request.setActivityId(1L);
        request.setName("   ");

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

        // Verify
        assertEquals(1, violations.size());
        ConstraintViolation<CreateApiKeyRequest> violation = violations.iterator().next();
        assertEquals("name", violation.getPropertyPath().toString());
        assertEquals("密钥名称不能为空", violation.getMessage());
    }

    @Test
    @DisplayName("CreateApiKeyRequest - 所有字段都无效")
    void testCreateApiKeyRequest_AllFieldsInvalid() {
        // Setup
        CreateApiKeyRequest request = new CreateApiKeyRequest();
        request.setActivityId(null);
        request.setName(null);

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

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

    @Test
    @DisplayName("CreateApiKeyRequest - Getter/Setter测试")
    void testCreateApiKeyRequest_GettersSetters() {
        // Setup
        CreateApiKeyRequest request = new CreateApiKeyRequest();
        
        // Test initial values
        assertNull(request.getActivityId());
        assertNull(request.getName());

        // Test setters and getters
        request.setActivityId(123L);
        assertEquals(123L, request.getActivityId());
        
        request.setName("新密钥");
        assertEquals("新密钥", request.getName());
        
        // Test overwrite
        request.setActivityId(456L);
        assertEquals(456L, request.getActivityId());
        
        request.setName("更新密钥");
        assertEquals("更新密钥", request.getName());
    }

    @Test
    @DisplayName("ErrorResponse - 基本功能测试")
    void testErrorResponse_BasicFunctionality() {
        // Setup
        ErrorResponse response = new ErrorResponse();
        
        // Test initial values
        assertNotNull(response);
        assertNull(response.getTimestamp());
        assertNull(response.getStatus());
        assertNull(response.getError());
        assertNull(response.getMessage());
        assertNull(response.getPath());
        assertNull(response.getDetails());
        assertNull(response.getTraceId());

        // Test setters
        java.time.OffsetDateTime now = java.time.OffsetDateTime.now();
        response.setTimestamp(now);
        assertEquals(now, response.getTimestamp());

        response.setStatus("200");
        assertEquals("200", response.getStatus());

        response.setError("OK");
        assertEquals("OK", response.getError());

        response.setMessage("成功消息");
        assertEquals("成功消息", response.getMessage());

        response.setPath("/api/test");
        assertEquals("/api/test", response.getPath());

        java.util.Map<String, Object> details = new java.util.HashMap<>();
        details.put("key", "value");
        response.setDetails(details);
        assertEquals(details, response.getDetails());
        assertEquals("value", response.getDetails().get("key"));

        response.setTraceId("trace123");
        assertEquals("trace123", response.getTraceId());
    }

    @Test
    @DisplayName("ErrorResponse - 构造器测试")
    void testErrorResponse_Constructors() {
        // Setup test data
        java.time.OffsetDateTime timestamp = java.time.OffsetDateTime.now();
        java.util.Map<String, String> stringErrors = new java.util.HashMap<>();
        stringErrors.put("field1", "error1");
        stringErrors.put("field2", "error2");
        java.util.Map<String, Object> errors = new java.util.HashMap<>(stringErrors);

        // Test full constructor
        ErrorResponse response1 = new ErrorResponse(timestamp, "/api/test", "400", "Bad Request", stringErrors);
        
        assertEquals(timestamp, response1.getTimestamp());
        assertEquals("/api/test", response1.getPath());
        assertEquals("400", response1.getStatus());
        assertEquals("Bad Request", response1.getMessage());
        assertEquals(errors, response1.getDetails());

        // Test default constructor and setters
        ErrorResponse response2 = new ErrorResponse();
        response2.setTimestamp(timestamp);
        response2.setPath("/api/other");
        response2.setStatus("500");
        response2.setMessage("Internal Error");
        response2.setDetails(errors);

        assertEquals(timestamp, response2.getTimestamp());
        assertEquals("/api/other", response2.getPath());
        assertEquals("500", response2.getStatus());
        assertEquals("Internal Error", response2.getMessage());
        assertEquals(errors, response2.getDetails());
    }

    @Test
    @DisplayName("ApiKeyResponse - 功能测试")
    void testApiKeyResponse_Functionality() {
        // Test default constructor
        ApiKeyResponse response1 = new ApiKeyResponse();
        assertNotNull(response1);
        assertNull(response1.getMessage());
        assertNull(response1.getData());
        assertNull(response1.getError());

        // Test static factory methods
        ApiKeyResponse successResponse = ApiKeyResponse.success("api-key-123");
        assertEquals("操作成功", successResponse.getMessage());
        assertEquals("api-key-123", successResponse.getData());
        assertNull(successResponse.getError());

        ApiKeyResponse errorResponse = ApiKeyResponse.error("密钥无效");
        assertEquals("操作失败", errorResponse.getMessage());
        assertNull(errorResponse.getData());
        assertEquals("密钥无效", errorResponse.getError());

        // Test parameterized constructor
        ApiKeyResponse customResponse = new ApiKeyResponse("自定义消息", "custom-data", "custom-error");
        assertEquals("自定义消息", customResponse.getMessage());
        assertEquals("custom-data", customResponse.getData());
        assertEquals("custom-error", customResponse.getError());
    }

    @Test
    @DisplayName("UseApiKeyRequest - 验证测试")
    void testUseApiKeyRequest() {
        // Setup
        UseApiKeyRequest request = new UseApiKeyRequest();
        
        // Test initial state
        assertNull(request.getApiKey());
        
        // Test setter and getter
        request.setApiKey("test-api-key-123");
        assertEquals("test-api-key-123", request.getApiKey());

        // Test with null
        request.setApiKey(null);
        assertNull(request.getApiKey());

        // Test with empty string
        request.setApiKey("");
        assertEquals("", request.getApiKey());

        // Test with special characters
        String specialKey = "api-key-!@#$%^&*()_+-={}[]|;':\",./<>?";
        request.setApiKey(specialKey);
        assertEquals(specialKey, request.getApiKey());
    }

    @Test
    @DisplayName("DTO对象序列化基础测试")
    void testDtoBasicSerialization() {
        // Test that DTOs can be instantiated and have expected structure
        CreateApiKeyRequest createRequest = new CreateApiKeyRequest();
        createRequest.setActivityId(1L);
        createRequest.setName("测试");

        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setMessage("测试错误");
        errorResponse.setStatus("400");

        ApiKeyResponse apiKeyResponse = new ApiKeyResponse();
        apiKeyResponse.setMessage("成功");
        apiKeyResponse.setData("key123");

        // Verify objects are properly initialized
        assertNotNull(createRequest);
        assertNotNull(errorResponse);
        assertNotNull(apiKeyResponse);

        // Verify values are set correctly
        assertEquals(Long.valueOf(1L), createRequest.getActivityId());
        assertEquals("测试", createRequest.getName());
        assertEquals("测试错误", errorResponse.getMessage());
        assertEquals("400", errorResponse.getStatus());
        assertEquals("成功", apiKeyResponse.getMessage());
        assertEquals("key123", apiKeyResponse.getData());
    }

    @Test
    @DisplayName("边界值验证测试")
    void testBoundaryValidation() {
        // Test with extreme values
        CreateApiKeyRequest request = new CreateApiKeyRequest();
        
        // Test with very long name
        StringBuilder longNameBuilder = new StringBuilder();
        for (int i = 0; i < 1000; i++) {
            longNameBuilder.append("a");
        }
        String longName = longNameBuilder.toString(); // 1000 characters
        request.setActivityId(Long.MAX_VALUE);
        request.setName(longName);

        Set<ConstraintViolation<CreateApiKeyRequest>> violations = validator.validate(request);
        assertTrue(violations.isEmpty(), "Long name should be valid");

        // Test with minimum valid values
        request.setActivityId(1L);
        request.setName("a");
        violations = validator.validate(request);
        assertTrue(violations.isEmpty(), "Minimum valid values should pass");

        // Test with maximum reasonable values
        request.setActivityId(Long.MAX_VALUE);
        StringBuilder nameBuilder = new StringBuilder();
        for (int i = 0; i < 100; i++) {
            nameBuilder.append("a");
        }
        request.setName(nameBuilder.toString()); // 100 characters
        violations = validator.validate(request);
        assertTrue(violations.isEmpty(), "Reasonable maximum values should pass");
    }
}