package com.mosquito.project.dto;

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 java.time.ZonedDateTime;
import java.util.Set;

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

@DisplayName("CreateActivityRequest验证测试")
class CreateActivityRequestValidationTest {

    private Validator validator;
    private CreateActivityRequest request;

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

    @Test
    @DisplayName("有效的请求应该通过验证")
    void shouldPassValidation_WhenValidRequest() {
        // Given
        request.setName("Test Activity");
        request.setStartTime(ZonedDateTime.parse("2025-03-01T10:00:00+08:00"));
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

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

    @Test
    @DisplayName("空名称应该失败验证")
    void shouldFailValidation_WhenNameIsNull() {
        // Given
        request.setName(null);
        request.setStartTime(ZonedDateTime.parse("2025-03-01T10:00:00+08:00"));
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

        // Then
        assertFalse(violations.isEmpty());
        assertEquals(1, violations.size());
        
        ConstraintViolation<CreateActivityRequest> violation = violations.iterator().next();
        assertEquals("name", violation.getPropertyPath().toString());
        assertEquals("活动名称不能为空", violation.getMessage());
    }

    @Test
    @DisplayName("空名称字符串应该失败验证")
    void shouldFailValidation_WhenNameIsEmpty() {
        // Given
        request.setName("");
        request.setStartTime(ZonedDateTime.parse("2025-03-01T10:00:00+08:00"));
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

        // Then
        assertFalse(violations.isEmpty());
        assertEquals(1, violations.size());
        
        ConstraintViolation<CreateActivityRequest> violation = violations.iterator().next();
        assertEquals("name", violation.getPropertyPath().toString());
        assertEquals("活动名称不能为空", violation.getMessage());
    }

    @Test
    @DisplayName("空名称空白字符串应该失败验证")
    void shouldFailValidation_WhenNameIsBlank() {
        // Given
        request.setName("   ");
        request.setStartTime(ZonedDateTime.parse("2025-03-01T10:00:00+08:00"));
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

        // Then
        assertFalse(violations.isEmpty());
        assertEquals(1, violations.size());
        
        ConstraintViolation<CreateActivityRequest> violation = violations.iterator().next();
        assertEquals("name", violation.getPropertyPath().toString());
        assertEquals("活动名称不能为空", violation.getMessage());
    }

    @Test
    @DisplayName("名称太长应该失败验证")
    void shouldFailValidation_WhenNameTooLong() {
        // Given - 创建101个字符的名称
        StringBuilder longName = new StringBuilder();
        for (int i = 0; i < 101; i++) {
            longName.append("a");
        }
        request.setName(longName.toString());
        request.setStartTime(ZonedDateTime.parse("2025-03-01T10:00:00+08:00"));
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

        // Then
        assertFalse(violations.isEmpty());
        assertEquals(1, violations.size());
        
        ConstraintViolation<CreateActivityRequest> violation = violations.iterator().next();
        assertEquals("name", violation.getPropertyPath().toString());
        assertEquals("活动名称不能超过100个字符", violation.getMessage());
    }

    @Test
    @DisplayName("名称刚好100个字符应该通过验证")
    void shouldPassValidation_WhenNameIsExactly100Chars() {
        // Given
        StringBuilder exactly100Name = new StringBuilder();
        for (int i = 0; i < 100; i++) {
            exactly100Name.append("a");
        }
        request.setName(exactly100Name.toString());
        request.setStartTime(ZonedDateTime.parse("2025-03-01T10:00:00+08:00"));
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

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

    @Test
    @DisplayName("开始时间为空应该失败验证")
    void shouldFailValidation_WhenStartTimeIsNull() {
        // Given
        request.setName("Test Activity");
        request.setStartTime(null);
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

        // Then
        assertFalse(violations.isEmpty());
        assertEquals(1, violations.size());
        
        ConstraintViolation<CreateActivityRequest> violation = violations.iterator().next();
        assertEquals("startTime", violation.getPropertyPath().toString());
        assertEquals("活动开始时间不能为空", violation.getMessage());
    }

    @Test
    @DisplayName("结束时间为空应该失败验证")
    void shouldFailValidation_WhenEndTimeIsNull() {
        // Given
        request.setName("Test Activity");
        request.setStartTime(ZonedDateTime.parse("2025-03-01T10:00:00+08:00"));
        request.setEndTime(null);

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

        // Then
        assertFalse(violations.isEmpty());
        assertEquals(1, violations.size());
        
        ConstraintViolation<CreateActivityRequest> violation = violations.iterator().next();
        assertEquals("endTime", violation.getPropertyPath().toString());
        assertEquals("活动结束时间不能为空", violation.getMessage());
    }

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

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

        // Then
        assertEquals(3, violations.size());
        
        boolean foundNameViolation = false;
        boolean foundStartTimeViolation = false;
        boolean foundEndTimeViolation = false;
        
        for (ConstraintViolation<CreateActivityRequest> violation : violations) {
            String property = violation.getPropertyPath().toString();
            if ("name".equals(property)) {
                foundNameViolation = true;
                assertEquals("活动名称不能为空", violation.getMessage());
            } else if ("startTime".equals(property)) {
                foundStartTimeViolation = true;
                assertEquals("活动开始时间不能为空", violation.getMessage());
            } else if ("endTime".equals(property)) {
                foundEndTimeViolation = true;
                assertEquals("活动结束时间不能为空", violation.getMessage());
            }
        }
        
        assertTrue(foundNameViolation);
        assertTrue(foundStartTimeViolation);
        assertTrue(foundEndTimeViolation);
    }

    @Test
    @DisplayName("有效请求与特殊字符应该通过验证")
    void shouldPassValidation_WithSpecialCharacters() {
        // Given
        request.setName("测试活动🔑_123");
        request.setStartTime(ZonedDateTime.parse("2025-03-01T10:00:00+08:00"));
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

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

    @Test
    @DisplayName("名称包含空白应该通过验证")
    void shouldPassValidation_WhenNameContainsWhitespace() {
        // Given
        request.setName("  Activity With Spaces  ");
        request.setStartTime(ZonedDateTime.parse("2025-03-01T10:00:00+08:00"));
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

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

    @Test
    @DisplayName("验证器消息应该包含具体字段名")
    void shouldIncludeFieldNamesInViolationMessages() {
        // Given
        request.setName(null);
        request.setStartTime(null);
        request.setEndTime(ZonedDateTime.parse("2025-03-31T23:59:59+08:00"));

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

        // Then
        assertEquals(2, violations.size());
        
        for (ConstraintViolation<CreateActivityRequest> violation : violations) {
            String property = violation.getPropertyPath().toString();
            assertTrue(property.equals("name") || property.equals("startTime"));
            assertTrue(violation.getMessage().contains("不能为空"));
        }
    }
}
