package com.mosquito.project.dto;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

@DisplayName("ErrorResponse 完整测试")
class ErrorResponseCompleteTest {

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

        // Then
        assertThat(response.getTimestamp()).isNull();
        assertThat(response.getStatus()).isNull();
        assertThat(response.getError()).isNull();
        assertThat(response.getMessage()).isNull();
        assertThat(response.getPath()).isNull();
        assertThat(response.getDetails()).isNull();
        assertThat(response.getTraceId()).isNull();
    }

    @Test
    @DisplayName("五参数构造函数应该创建完整的ErrorResponse对象")
    void shouldCreateCompleteErrorResponse_whenUsingFiveParamConstructor() {
        // Given
        OffsetDateTime timestamp = OffsetDateTime.now();
        String path = "/api/test";
        String code = "400";
        String message = "Validation failed";
        Map<String, String> errors = new HashMap<>();
        errors.put("field1", "must not be empty");
        errors.put("field2", "invalid format");

        // When
        ErrorResponse response = new ErrorResponse(timestamp, path, code, message, errors);

        // Then
        assertThat(response.getTimestamp()).isEqualTo(timestamp);
        assertThat(response.getPath()).isEqualTo(path);
        assertThat(response.getStatus()).isEqualTo(code);
        assertThat(response.getMessage()).isEqualTo(message);
        assertThat(response.getDetails()).isNotNull();
        assertThat(response.getDetails()).hasSize(2);
        assertThat(response.getDetails().get("field1")).isEqualTo("must not be empty");
        assertThat(response.getDetails().get("field2")).isEqualTo("invalid format");
    }

    @Test
    @DisplayName("五参数构造函数应该在errors为null时不设置details")
    void shouldNotSetDetails_whenErrorsIsNull() {
        // Given
        OffsetDateTime timestamp = OffsetDateTime.now();
        String path = "/api/test";
        String code = "500";
        String message = "Internal error";

        // When
        ErrorResponse response = new ErrorResponse(timestamp, path, code, message, null);

        // Then
        assertThat(response.getTimestamp()).isEqualTo(timestamp);
        assertThat(response.getPath()).isEqualTo(path);
        assertThat(response.getStatus()).isEqualTo(code);
        assertThat(response.getMessage()).isEqualTo(message);
        assertThat(response.getDetails()).isNull();
    }

    @Test
    @DisplayName("五参数构造函数应该在errors为空map时设置空details")
    void shouldSetEmptyDetails_whenErrorsIsEmpty() {
        // Given
        OffsetDateTime timestamp = OffsetDateTime.now();
        Map<String, String> emptyErrors = new HashMap<>();

        // When
        ErrorResponse response = new ErrorResponse(timestamp, "/api/test", "200", "OK", emptyErrors);

        // Then
        assertThat(response.getDetails()).isNotNull();
        assertThat(response.getDetails()).isEmpty();
    }

    @Test
    @DisplayName("timestamp setter/getter 应该正常工作")
    void shouldHandleTimestamp_whenUsingGetterAndSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();
        OffsetDateTime timestamp = OffsetDateTime.now();

        // When
        response.setTimestamp(timestamp);

        // Then
        assertThat(response.getTimestamp()).isEqualTo(timestamp);
    }

    @Test
    @DisplayName("status setter/getter 应该正常工作")
    void shouldHandleStatus_whenUsingGetterAndSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();

        // When - HTTP状态码
        response.setStatus("400");
        assertThat(response.getStatus()).isEqualTo("400");

        // When - 错误状态
        response.setStatus("error");
        assertThat(response.getStatus()).isEqualTo("error");

        // When - null
        response.setStatus(null);
        assertThat(response.getStatus()).isNull();
    }

    @Test
    @DisplayName("error setter/getter 应该正常工作")
    void shouldHandleError_whenUsingGetterAndSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();

        // When
        response.setError("Bad Request");

        // Then
        assertThat(response.getError()).isEqualTo("Bad Request");
    }

    @Test
    @DisplayName("message setter/getter 应该正常工作")
    void shouldHandleMessage_whenUsingGetterAndSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();

        // When
        response.setMessage("Something went wrong");

        // Then
        assertThat(response.getMessage()).isEqualTo("Something went wrong");
    }

    @Test
    @DisplayName("path setter/getter 应该正常工作")
    void shouldHandlePath_whenUsingGetterAndSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();

        // When
        response.setPath("/api/users/123");

        // Then
        assertThat(response.getPath()).isEqualTo("/api/users/123");
    }

    @Test
    @DisplayName("details setter/getter 应该正常工作")
    void shouldHandleDetails_whenUsingGetterAndSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();
        Map<String, Object> details = new HashMap<>();
        details.put("errorCode", "E001");
        details.put("retryAfter", 60);

        // When
        response.setDetails(details);

        // Then
        assertThat(response.getDetails()).isEqualTo(details);
        assertThat(response.getDetails().get("errorCode")).isEqualTo("E001");
        assertThat(response.getDetails().get("retryAfter")).isEqualTo(60);
    }

    @Test
    @DisplayName("details 应该处理null值")
    void shouldHandleNullDetails_whenUsingSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();

        // When
        response.setDetails(null);

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

    @Test
    @DisplayName("details 应该处理空map")
    void shouldHandleEmptyDetails_whenUsingSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();
        Map<String, Object> emptyDetails = new HashMap<>();

        // When
        response.setDetails(emptyDetails);

        // Then
        assertThat(response.getDetails()).isNotNull();
        assertThat(response.getDetails()).isEmpty();
    }

    @Test
    @DisplayName("traceId setter/getter 应该正常工作")
    void shouldHandleTraceId_whenUsingGetterAndSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();
        String traceId = "trace-abc123-def456";

        // When
        response.setTraceId(traceId);

        // Then
        assertThat(response.getTraceId()).isEqualTo(traceId);
    }

    @Test
    @DisplayName("traceId 应该处理null值")
    void shouldHandleNullTraceId_whenUsingSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();

        // When
        response.setTraceId(null);

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

    @Test
    @DisplayName("完整ErrorResponse构建应该正常工作")
    void shouldBuildCompleteErrorResponse_whenUsingAllSetters() {
        // Given
        ErrorResponse response = new ErrorResponse();
        OffsetDateTime timestamp = OffsetDateTime.now();
        Map<String, Object> details = new HashMap<>();
        details.put("validationErrors", Map.of("email", "invalid format"));

        // When
        response.setTimestamp(timestamp);
        response.setStatus("422");
        response.setError("Unprocessable Entity");
        response.setMessage("Request validation failed");
        response.setPath("/api/orders");
        response.setDetails(details);
        response.setTraceId("req-xyz789");

        // Then
        assertThat(response.getTimestamp()).isEqualTo(timestamp);
        assertThat(response.getStatus()).isEqualTo("422");
        assertThat(response.getError()).isEqualTo("Unprocessable Entity");
        assertThat(response.getMessage()).isEqualTo("Request validation failed");
        assertThat(response.getPath()).isEqualTo("/api/orders");
        assertThat(response.getDetails()).isEqualTo(details);
        assertThat(response.getTraceId()).isEqualTo("req-xyz789");
    }

    @Test
    @DisplayName("不同HTTP状态码的处理")
    void shouldHandleVariousHttpStatusCodes() {
        // Given
        ErrorResponse response400 = new ErrorResponse();
        ErrorResponse response401 = new ErrorResponse();
        ErrorResponse response403 = new ErrorResponse();
        ErrorResponse response404 = new ErrorResponse();
        ErrorResponse response500 = new ErrorResponse();

        // When
        response400.setStatus("400");
        response400.setError("Bad Request");
        response400.setMessage("Invalid request parameters");

        response401.setStatus("401");
        response401.setError("Unauthorized");
        response401.setMessage("Authentication required");

        response403.setStatus("403");
        response403.setError("Forbidden");
        response403.setMessage("Access denied");

        response404.setStatus("404");
        response404.setError("Not Found");
        response404.setMessage("Resource not found");

        response500.setStatus("500");
        response500.setError("Internal Server Error");
        response500.setMessage("An unexpected error occurred");

        // Then
        assertThat(response400.getStatus()).isEqualTo("400");
        assertThat(response401.getStatus()).isEqualTo("401");
        assertThat(response403.getStatus()).isEqualTo("403");
        assertThat(response404.getStatus()).isEqualTo("404");
        assertThat(response500.getStatus()).isEqualTo("500");
    }

    @Test
    @DisplayName("details应该支持复杂数据结构")
    void shouldSupportComplexDetails_whenUsingSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();
        Map<String, Object> complexDetails = new HashMap<>();
        
        Map<String, Object> nestedMap = new HashMap<>();
        nestedMap.put("code", "FIELD_ERROR");
        nestedMap.put("field", "email");
        nestedMap.put("rejectedValue", "invalid-email");
        
        complexDetails.put("errors", new Object[]{nestedMap});
        complexDetails.put("timestamp", OffsetDateTime.now().toString());
        complexDetails.put("requestId", "req-12345");

        // When
        response.setDetails(complexDetails);

        // Then
        assertThat(response.getDetails()).isNotNull();
        assertThat(response.getDetails().get("requestId")).isEqualTo("req-12345");
    }

    @Test
    @DisplayName("边界值：超长message")
    void shouldHandleLongMessage_whenUsingSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();
        String longMessage = "Error: ".repeat(1000);

        // When
        response.setMessage(longMessage);

        // Then
        assertThat(response.getMessage()).hasSize(longMessage.length());
    }

    @Test
    @DisplayName("边界值：特殊字符在message中")
    void shouldHandleSpecialCharacters_whenUsingSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();
        String messageWithSpecialChars = "Error: <script>alert('xss')</script> \\n\\t\\r 中文测试 🎉";

        // When
        response.setMessage(messageWithSpecialChars);

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

    @Test
    @DisplayName("边界值：各种path格式")
    void shouldHandleVariousPathFormats_whenUsingSetter() {
        // Given
        ErrorResponse response = new ErrorResponse();

        // When - 正常路径
        response.setPath("/api/users");
        assertThat(response.getPath()).isEqualTo("/api/users");

        // When - 带参数的路径
        response.setPath("/api/users/123/orders?status=pending");
        assertThat(response.getPath()).isEqualTo("/api/users/123/orders?status=pending");

        // When - 根路径
        response.setPath("/");
        assertThat(response.getPath()).isEqualTo("/");

        // When - 空路径
        response.setPath("");
        assertThat(response.getPath()).isEmpty();
    }

    @Test
    @DisplayName("多次修改属性应该保持最新值")
    void shouldMaintainLatestValue_whenModifiedMultipleTimes() {
        // Given
        ErrorResponse response = new ErrorResponse();

        // When - 多次修改status
        response.setStatus("400");
        assertThat(response.getStatus()).isEqualTo("400");
        
        response.setStatus("401");
        assertThat(response.getStatus()).isEqualTo("401");
        
        response.setStatus("500");
        assertThat(response.getStatus()).isEqualTo("500");

        // When - 多次修改message
        response.setMessage("First error");
        assertThat(response.getMessage()).isEqualTo("First error");
        
        response.setMessage("Second error");
        assertThat(response.getMessage()).isEqualTo("Second error");
    }

    @Test
    @DisplayName("构造函数创建的details应该是独立的副本")
    void shouldCreateIndependentDetailsCopy_whenUsingConstructor() {
        // Given
        Map<String, String> originalErrors = new HashMap<>();
        originalErrors.put("field", "error");
        
        ErrorResponse response = new ErrorResponse(
            OffsetDateTime.now(), 
            "/test", 
            "400", 
            "Error", 
            originalErrors
        );

        // When - 修改原始map
        originalErrors.put("newField", "newError");

        // Then - response中的details不应受影响
        assertThat(response.getDetails()).doesNotContainKey("newField");
        assertThat(response.getDetails()).containsKey("field");
    }
}
