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

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

/**
 * ShortenRequest DTO验证和功能测试
 */
@DisplayName("ShortenRequest DTO测试")
class ShortenRequestTest {

    private Validator validator;
    private ShortenRequest request;

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

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

        @Test
        @DisplayName("有效的URL应该通过验证")
        void shouldPassValidation_WhenValidUrl() {
            // Given
            String validUrl = "https://www.example.com/very-long-path?param=value&other=test";
            request.setOriginalUrl(validUrl);

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

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

        @ParameterizedTest
        @NullAndEmptySource
        @DisplayName("空值URL应该失败验证")
        void shouldFailValidation_WhenUrlIsNullOrEmpty(String url) {
            // Given
            request.setOriginalUrl(url);

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

            // Then
            assertFalse(violations.isEmpty(), "空URL应该验证失败");
            assertTrue(
                violations.stream().anyMatch(violation ->
                    "originalUrl".equals(violation.getPropertyPath().toString())
                        && "原始URL不能为空".equals(violation.getMessage())),
                "应包含原始URL不能为空的错误"
            );
        }

        @Test
        @DisplayName("URL太短应该失败验证")
        void shouldFailValidation_WhenUrlTooShort() {
            // Given
            String shortUrl = "http://a";
            request.setOriginalUrl(shortUrl);

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

            // Then
            assertFalse(violations.isEmpty(), "太短的URL应该验证失败");
            assertEquals(1, violations.size());
            
            ConstraintViolation<ShortenRequest> violation = violations.iterator().next();
            assertEquals("URL长度必须在10-2048个字符之间", violation.getMessage());
        }

        @Test
        @DisplayName("URL太长应该失败验证")
        void shouldFailValidation_WhenUrlTooLong() {
            // Given - 创建2049个字符的URL
            String baseUrl = "https://example.com/";
            int targetLength = 2049;
            StringBuilder longUrl = new StringBuilder(baseUrl);
            for (int i = 0; i < targetLength - baseUrl.length(); i++) {
                longUrl.append("a");
            }
            request.setOriginalUrl(longUrl.toString());

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

            // Then
            assertFalse(violations.isEmpty(), "太长的URL应该验证失败");
            assertEquals(1, violations.size());
            
            ConstraintViolation<ShortenRequest> violation = violations.iterator().next();
            assertEquals("URL长度必须在10-2048个字符之间", violation.getMessage());
        }

        @Test
        @DisplayName("边界长度URL应该通过验证")
        void shouldPassValidation_WhenUrlIsAtBoundaryLength() {
            // Given - 恰好10个字符的URL
            String boundaryUrl = "http://a.c";
            request.setOriginalUrl(boundaryUrl);

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

            // Then
            assertTrue(violations.isEmpty(), "边界长度的URL应该通过验证");
        }

        @ParameterizedTest
        @ValueSource(strings = {
            "https://www.example.com",
            "http://localhost:8080/api/test",
            "ftp://files.example.com/download",
            "https://subdomain.example.co.uk/path/to/resource?query=value&filter=test#section"
        })
        @DisplayName("各种有效URL格式应该通过验证")
        void shouldPassValidation_WithVariousValidUrlFormats(String validUrl) {
            // Given
            request.setOriginalUrl(validUrl);

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

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

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

        @Test
        @DisplayName("getter和setter应该正常工作")
        void shouldWorkCorrectly_GetterAndSetter() {
            // Given
            String testUrl = "https://test.example.com/path";

            // When
            request.setOriginalUrl(testUrl);

            // Then
            assertEquals(testUrl, request.getOriginalUrl());
        }

        @Test
        @DisplayName("多次设置URL应该正确更新")
        void shouldUpdateCorrectly_WhenSetMultipleTimes() {
            // Given
            String firstUrl = "https://first.example.com";
            String secondUrl = "https://second.example.com";
            
            // When & Then
            request.setOriginalUrl(firstUrl);
            assertEquals(firstUrl, request.getOriginalUrl());
            
            request.setOriginalUrl(secondUrl);
            assertEquals(secondUrl, request.getOriginalUrl());
            assertNotEquals(firstUrl, request.getOriginalUrl());
        }

        @Test
        @DisplayName("设置null应该正确处理")
        void shouldHandleNullValue() {
            // Given
            request.setOriginalUrl("https://example.com");
            assertNotNull(request.getOriginalUrl());

            // When
            request.setOriginalUrl(null);

            // Then
            assertNull(request.getOriginalUrl());
        }
    }

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

        @Test
        @DisplayName("URL包含特殊字符应该通过验证")
        void shouldPassValidation_WhenUrlContainsSpecialCharacters() {
            // Given - URL包含各种特殊字符
            String specialCharsUrl = "https://example.com/path-with_dashes/path.with.dots?param=value&other=test%20encoded&emoji=🎉";
            request.setOriginalUrl(specialCharsUrl);

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

            // Then
            assertTrue(violations.isEmpty(), "包含特殊字符的URL应该通过验证");
        }

        @Test
        @DisplayName("URL包含Unicode字符应该通过验证")
        void shouldPassValidation_WhenUrlContainsUnicode() {
            // Given - 包含中文的URL
            String unicodeUrl = "https://example.com/测试路径?参数=值&其他=测试";
            request.setOriginalUrl(unicodeUrl);

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

            // Then
            assertTrue(violations.isEmpty(), "包含Unicode字符的URL应该通过验证");
        }

        @Test
        @DisplayName("恰好2048字符的URL应该通过验证")
        void shouldPassValidation_WhenUrlIsExactly2048Chars() {
            // Given - 创建恰好2048个字符的URL
            String baseUrl = "https://example.com/";
            int targetLength = 2048;
            StringBuilder exactLengthUrl = new StringBuilder(baseUrl);
            for (int i = 0; i < targetLength - baseUrl.length(); i++) {
                exactLengthUrl.append("a");
            }
            String finalUrl = exactLengthUrl.toString();
            request.setOriginalUrl(finalUrl);

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

            // Then
            assertEquals(2048, finalUrl.length(), "URL长度应该是2048字符");
            assertTrue(violations.isEmpty(), "恰好2048字符的URL应该通过验证");
        }
    }
}
