package com.mosquito.project.web;

import com.mosquito.project.config.ApiVersion;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.web.servlet.ModelAndView;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
@DisplayName("ApiResponseWrapperInterceptor 测试")
class ApiResponseWrapperInterceptorTest {

    @Mock
    private HttpServletRequest request;

    @Mock
    private HttpServletResponse response;

    @Mock
    private Object handler;

    @Mock
    private ModelAndView modelAndView;

    private ApiResponseWrapperInterceptor interceptor;

    @BeforeEach
    void setUp() {
        interceptor = new ApiResponseWrapperInterceptor();
    }

    @Test
    @DisplayName("preHandle应该设置startTime属性并返回true")
    void shouldSetStartTimeAndReturnTrue_whenPreHandle() {
        // When
        boolean result = interceptor.preHandle(request, response, handler);

        // Then
        assertThat(result).isTrue();
        verify(request).setAttribute(eq("startTime"), anyLong());
    }

    @Test
    @DisplayName("postHandle应该为成功响应设置API版本头")
    void shouldSetApiVersionHeader_whenResponseIsSuccessful() {
        // Given
        when(response.getStatus()).thenReturn(200);
        when(request.getHeader(ApiVersion.HEADER_NAME)).thenReturn("v1");

        // When
        interceptor.postHandle(request, response, handler, modelAndView);

        // Then
        verify(response).setHeader(ApiVersion.HEADER_NAME, "v1");
    }

    @Test
    @DisplayName("postHandle应该使用默认版本当请求头为null")
    void shouldUseDefaultVersion_whenRequestHeaderIsNull() {
        // Given
        when(response.getStatus()).thenReturn(200);
        when(request.getHeader(ApiVersion.HEADER_NAME)).thenReturn(null);

        // When
        interceptor.postHandle(request, response, handler, modelAndView);

        // Then
        verify(response).setHeader(ApiVersion.HEADER_NAME, ApiVersion.DEFAULT_VERSION);
    }

    @Test
    @DisplayName("postHandle应该使用默认版本当请求头为空白")
    void shouldUseDefaultVersion_whenRequestHeaderIsBlank() {
        // Given
        when(response.getStatus()).thenReturn(200);
        when(request.getHeader(ApiVersion.HEADER_NAME)).thenReturn("   ");

        // When
        interceptor.postHandle(request, response, handler, modelAndView);

        // Then
        verify(response).setHeader(ApiVersion.HEADER_NAME, ApiVersion.DEFAULT_VERSION);
    }

    @Test
    @DisplayName("postHandle不应该为错误响应设置版本头")
    void shouldNotSetVersionHeader_whenResponseIsError() {
        // Given
        when(response.getStatus()).thenReturn(400);

        // When
        interceptor.postHandle(request, response, handler, modelAndView);

        // Then
        verify(response, never()).setHeader(anyString(), anyString());
    }

    @Test
    @DisplayName("postHandle不应该为服务器错误设置版本头")
    void shouldNotSetVersionHeader_whenResponseIsServerError() {
        // Given
        when(response.getStatus()).thenReturn(500);

        // When
        interceptor.postHandle(request, response, handler, modelAndView);

        // Then
        verify(response, never()).setHeader(anyString(), anyString());
    }

    @Test
    @DisplayName("afterCompletion应该记录API请求日志")
    void shouldLogApiRequest_whenAfterCompletion() {
        // Given
        when(request.getAttribute("startTime")).thenReturn(System.currentTimeMillis() - 100);
        when(request.getRequestURI()).thenReturn("/api/v1/activities");
        when(request.getMethod()).thenReturn("GET");

        // When
        interceptor.afterCompletion(request, response, handler, null);

        // Then - 验证没有抛出异常
        verify(request).getAttribute("startTime");
        verify(request, atLeastOnce()).getRequestURI();
    }

    @Test
    @DisplayName("afterCompletion应该处理非API请求")
    void shouldHandleNonApiRequest_whenAfterCompletion() {
        // Given
        when(request.getAttribute("startTime")).thenReturn(System.currentTimeMillis());
        when(request.getRequestURI()).thenReturn("/health");

        // When
        interceptor.afterCompletion(request, response, handler, null);

        // Then - 验证没有抛出异常
        verify(request).getAttribute("startTime");
        verify(request).getRequestURI();
    }

    @Test
    @DisplayName("afterCompletion应该处理异常情况")
    void shouldHandleException_whenAfterCompletion() {
        // Given
        when(request.getAttribute("startTime")).thenReturn(System.currentTimeMillis());
        when(request.getRequestURI()).thenReturn("/api/v1/test");
        when(request.getMethod()).thenReturn("POST");
        Exception exception = new RuntimeException("Test exception");

        // When
        interceptor.afterCompletion(request, response, handler, exception);

        // Then - 验证没有抛出异常
        verify(request).getAttribute("startTime");
    }

    @Test
    @DisplayName("postHandle应该处理2xx范围内的所有成功状态码")
    void shouldHandleAllSuccessStatusCodes_whenPostHandle() {
        // Test 200 OK
        when(response.getStatus()).thenReturn(200);
        when(request.getHeader(ApiVersion.HEADER_NAME)).thenReturn("v1");
        interceptor.postHandle(request, response, handler, modelAndView);
        verify(response).setHeader(ApiVersion.HEADER_NAME, "v1");

        // Test 201 Created
        reset(response, request);
        when(response.getStatus()).thenReturn(201);
        when(request.getHeader(ApiVersion.HEADER_NAME)).thenReturn("v1");
        interceptor.postHandle(request, response, handler, modelAndView);
        verify(response).setHeader(ApiVersion.HEADER_NAME, "v1");

        // Test 204 No Content
        reset(response, request);
        when(response.getStatus()).thenReturn(204);
        when(request.getHeader(ApiVersion.HEADER_NAME)).thenReturn("v1");
        interceptor.postHandle(request, response, handler, modelAndView);
        verify(response).setHeader(ApiVersion.HEADER_NAME, "v1");
    }

    @Test
    @DisplayName("postHandle应该拒绝3xx重定向状态码")
    void shouldNotSetHeaderForRedirectStatus_whenPostHandle() {
        // Given
        when(response.getStatus()).thenReturn(302);

        // When
        interceptor.postHandle(request, response, handler, modelAndView);

        // Then
        verify(response, never()).setHeader(anyString(), anyString());
    }
}
