package cn.novalon.manage.sys.security;

import org.junit.jupiter.api.BeforeEach;
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.http.HttpHeaders;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class JwtAuthenticationFilterTest {

    @Mock
    private JwtTokenProvider jwtTokenProvider;

    @Mock
    private WebFilterChain webFilterChain;

    private JwtAuthenticationFilter jwtAuthenticationFilter;

    @BeforeEach
    void setUp() {
        jwtAuthenticationFilter = new JwtAuthenticationFilter(jwtTokenProvider);
    }

    @Test
    void testFilter_WithValidToken() {
        String validToken = "valid.jwt.token";
        Long userId = 1L;
        
        when(jwtTokenProvider.validateToken(validToken)).thenReturn(true);
        when(jwtTokenProvider.getUserIdFromToken(validToken)).thenReturn(userId);
        when(webFilterChain.filter(any(ServerWebExchange.class))).thenReturn(Mono.empty());
        
        MockServerHttpRequest request = MockServerHttpRequest.get("/api/test")
                .header(HttpHeaders.AUTHORIZATION, "Bearer " + validToken)
                .build();
        ServerWebExchange exchange = MockServerWebExchange.from(request);
        
        Mono<Void> result = jwtAuthenticationFilter.filter(exchange, webFilterChain);
        
        StepVerifier.create(result)
                .verifyComplete();
        
        verify(jwtTokenProvider).validateToken(validToken);
        verify(jwtTokenProvider).getUserIdFromToken(validToken);
        verify(webFilterChain).filter(any(ServerWebExchange.class));
    }

    @Test
    void testFilter_WithInvalidToken() {
        String invalidToken = "invalid.jwt.token";
        
        when(jwtTokenProvider.validateToken(invalidToken)).thenReturn(false);
        when(webFilterChain.filter(any(ServerWebExchange.class))).thenReturn(Mono.empty());
        
        MockServerHttpRequest request = MockServerHttpRequest.get("/api/test")
                .header(HttpHeaders.AUTHORIZATION, "Bearer " + invalidToken)
                .build();
        ServerWebExchange exchange = MockServerWebExchange.from(request);
        
        Mono<Void> result = jwtAuthenticationFilter.filter(exchange, webFilterChain);
        
        StepVerifier.create(result)
                .verifyComplete();
        
        verify(jwtTokenProvider).validateToken(invalidToken);
        verify(webFilterChain).filter(any(ServerWebExchange.class));
    }

    @Test
    void testFilter_WithoutToken() {
        when(webFilterChain.filter(any(ServerWebExchange.class))).thenReturn(Mono.empty());
        
        MockServerHttpRequest request = MockServerHttpRequest.get("/api/test")
                .build();
        ServerWebExchange exchange = MockServerWebExchange.from(request);
        
        Mono<Void> result = jwtAuthenticationFilter.filter(exchange, webFilterChain);
        
        StepVerifier.create(result)
                .verifyComplete();
        
        verify(webFilterChain).filter(any(ServerWebExchange.class));
    }

    @Test
    void testFilter_WithMalformedToken() {
        String malformedToken = "Bearer";
        
        when(webFilterChain.filter(any(ServerWebExchange.class))).thenReturn(Mono.empty());
        
        MockServerHttpRequest request = MockServerHttpRequest.get("/api/test")
                .header(HttpHeaders.AUTHORIZATION, malformedToken)
                .build();
        ServerWebExchange exchange = MockServerWebExchange.from(request);
        
        Mono<Void> result = jwtAuthenticationFilter.filter(exchange, webFilterChain);
        
        StepVerifier.create(result)
                .verifyComplete();
        
        verify(webFilterChain).filter(any(ServerWebExchange.class));
    }

    @Test
    void testFilter_WithTokenWithoutBearerPrefix() {
        String tokenWithoutBearer = "just.a.token";
        
        when(webFilterChain.filter(any(ServerWebExchange.class))).thenReturn(Mono.empty());
        
        MockServerHttpRequest request = MockServerHttpRequest.get("/api/test")
                .header(HttpHeaders.AUTHORIZATION, tokenWithoutBearer)
                .build();
        ServerWebExchange exchange = MockServerWebExchange.from(request);
        
        Mono<Void> result = jwtAuthenticationFilter.filter(exchange, webFilterChain);
        
        StepVerifier.create(result)
                .verifyComplete();
        
        verify(webFilterChain).filter(any(ServerWebExchange.class));
    }
}