package com.mosquito.project.exception;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.springframework.http.HttpStatus;

import java.util.HashMap;
import java.util.Map;

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

/**
 * 异常类测试 - 提升异常处理模块覆盖率
 */
class ExceptionTest {

    @Test
    @DisplayName("BusinessException - 默认构造器")
    void testBusinessExceptionDefaultConstructor() {
        BusinessException exception = new BusinessException("Test error");
        
        assertEquals("Test error", exception.getMessage());
        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, exception.getStatus());
        assertEquals("BUSINESS_ERROR", exception.getErrorCode());
        assertNotNull(exception.getDetails());
        assertTrue(exception.getDetails().isEmpty());
    }

    @Test
    @DisplayName("BusinessException - 带状态码构造器")
    void testBusinessExceptionWithStatus() {
        BusinessException exception = new BusinessException("Bad request", HttpStatus.BAD_REQUEST);
        
        assertEquals("Bad request", exception.getMessage());
        assertEquals(HttpStatus.BAD_REQUEST, exception.getStatus());
        assertEquals("BUSINESS_ERROR", exception.getErrorCode());
    }

    @Test
    @DisplayName("BusinessException - 带错误码构造器")
    void testBusinessExceptionWithErrorCode() {
        BusinessException exception = new BusinessException("Custom error", "CUSTOM_ERROR");
        
        assertEquals("Custom error", exception.getMessage());
        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, exception.getStatus());
        assertEquals("CUSTOM_ERROR", exception.getErrorCode());
    }

    @Test
    @DisplayName("BusinessException - 带状态码和错误码构造器")
    void testBusinessExceptionWithStatusAndErrorCode() {
        BusinessException exception = new BusinessException("Custom error", HttpStatus.NOT_FOUND, "NOT_FOUND");
        
        assertEquals("Custom error", exception.getMessage());
        assertEquals(HttpStatus.NOT_FOUND, exception.getStatus());
        assertEquals("NOT_FOUND", exception.getErrorCode());
    }

    @Test
    @DisplayName("BusinessException - 带详细信息构造器")
    void testBusinessExceptionWithDetails() {
        Map<String, Object> details = new HashMap<>();
        details.put("field", "username");
        details.put("value", "invalid");
        
        BusinessException exception = new BusinessException("Validation failed", details);
        
        assertEquals("Validation failed", exception.getMessage());
        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, exception.getStatus());
        assertEquals("BUSINESS_ERROR", exception.getErrorCode());
        assertEquals(details, exception.getDetails());
        assertEquals(2, exception.getDetails().size());
    }

    @Test
    @DisplayName("ResourceNotFoundException - 默认构造器")
    void testResourceNotFoundExceptionDefaultConstructor() {
        ResourceNotFoundException exception = new ResourceNotFoundException("User", "123");
        
        assertEquals("User not found with id: 123", exception.getMessage());
        assertEquals("User", exception.getResourceType());
        assertEquals("123", exception.getResourceId());
    }

    @Test
    @DisplayName("ResourceNotFoundException - 仅消息构造器")
    void testResourceNotFoundExceptionMessageOnly() {
        ResourceNotFoundException exception = new ResourceNotFoundException("Custom not found message");
        
        assertEquals("Custom not found message", exception.getMessage());
        assertEquals("Resource", exception.getResourceType());
        assertEquals("unknown", exception.getResourceId());
    }

    @Test
    @DisplayName("ValidationException - 默认构造器")
    void testValidationExceptionDefaultConstructor() {
        ValidationException exception = new ValidationException("Validation failed");
        
        assertEquals("Validation failed", exception.getMessage());
        assertNotNull(exception.getErrors());
        assertTrue(exception.getErrors().isEmpty());
    }

    @Test
    @DisplayName("ValidationException - 带错误详情构造器")
    void testValidationExceptionWithErrors() {
        Map<String, String> errors = new HashMap<>();
        errors.put("username", "不能为空");
        errors.put("email", "格式不正确");
        
        ValidationException exception = new ValidationException("Validation failed", errors);
        
        assertEquals("Validation failed", exception.getMessage());
        assertEquals(errors, exception.getErrors());
        assertEquals(2, exception.getErrors().size());
        assertTrue(exception.getErrors().containsKey("username"));
        assertTrue(exception.getErrors().containsKey("email"));
        assertEquals("不能为空", exception.getErrors().get("username"));
        assertEquals("格式不正确", exception.getErrors().get("email"));
    }

    @Test
    @DisplayName("ValidationException - null错误详情")
    void testValidationExceptionWithNullErrors() {
        ValidationException exception = new ValidationException("Simple error", null);
        
        assertEquals("Simple error", exception.getMessage());
        // 当传入null时，errors字段实际是null，这是预期行为
        assertNull(exception.getErrors());
    }

    @Test
    @DisplayName("异常继承关系验证")
    void testExceptionInheritance() {
        BusinessException businessEx = new BusinessException("Business error");
        ResourceNotFoundException resourceEx = new ResourceNotFoundException("Resource error");
        ValidationException validationEx = new ValidationException("Validation error");
        
        // 验证所有异常都继承自RuntimeException
        assertTrue(businessEx instanceof RuntimeException);
        assertTrue(resourceEx instanceof RuntimeException);
        assertTrue(validationEx instanceof RuntimeException);
        
        // 验证具体异常类型
        assertTrue(businessEx instanceof BusinessException);
        assertTrue(resourceEx instanceof ResourceNotFoundException);
        assertTrue(validationEx instanceof ValidationException);
    }

    @Test
    @DisplayName("异常详细信息修改测试")
    void testExceptionDetailsModification() {
        Map<String, Object> details = new HashMap<>();
        details.put("field1", "value1");
        
        BusinessException exception = new BusinessException("Error", details);
        
        // 验证可以修改details（如果业务需要）
        exception.getDetails().put("field2", "value2");
        
        assertEquals(2, exception.getDetails().size());
        assertTrue(exception.getDetails().containsKey("field1"));
        assertTrue(exception.getDetails().containsKey("field2"));
    }

    @Test
    @DisplayName("异常消息国际化测试")
    void testExceptionMessageInternationalization() {
        BusinessException exception = new BusinessException("国际化错误消息");
        
        assertEquals("国际化错误消息", exception.getMessage());
        
        // 验证消息格式
        String message = exception.getMessage();
        assertNotNull(message);
        assertFalse(message.trim().isEmpty());
        assertTrue(message.length() > 0);
    }

    @Test
    @DisplayName("异常链测试")
    void testExceptionChaining() {
        // 使用现有构造器创建异常链
        RuntimeException cause = new RuntimeException("Root cause");
        BusinessException exception = new BusinessException("Wrapped error", cause);
        
        assertEquals("Wrapped error", exception.getMessage());
        assertEquals(cause, exception.getCause());
        assertEquals("Root cause", exception.getCause().getMessage());
    }
}