package cn.novalon.gym.manage.gateway.filter;

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.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.HttpMethod;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import reactor.core.publisher.Mono;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class CompressionFilterTest {

    private CompressionFilter compressionFilter;

    @Mock
    private GatewayFilterChain chain;

    @BeforeEach
    void setUp() {
        compressionFilter = new CompressionFilter();
        compressionFilter.setCompressionEnabled(true);
        when(chain.filter(any())).thenReturn(Mono.empty());
    }

    @Test
    void testFilter_WithGzipSupport() {
        MockServerHttpRequest request = MockServerHttpRequest
                .get("/api/test")
                .header("Accept-Encoding", "gzip, deflate")
                .build();

        MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();

        compressionFilter.filter(exchange, chain).block();

        assertEquals("gzip", exchange.getResponse().getHeaders().getFirst("Content-Encoding"));
        verify(chain).filter(any());
    }

    @Test
    void testFilter_WithDeflateSupport() {
        MockServerHttpRequest request = MockServerHttpRequest
                .get("/api/test")
                .header("Accept-Encoding", "deflate")
                .build();

        MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();

        compressionFilter.filter(exchange, chain).block();

        assertEquals("deflate", exchange.getResponse().getHeaders().getFirst("Content-Encoding"));
        verify(chain).filter(any());
    }

    @Test
    void testFilter_NoAcceptEncoding() {
        MockServerHttpRequest request = MockServerHttpRequest
                .get("/api/test")
                .build();

        MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();

        compressionFilter.filter(exchange, chain).block();

        assertNull(exchange.getResponse().getHeaders().getFirst("Content-Encoding"));
        verify(chain).filter(any());
    }

    @Test
    void testFilter_CompressionDisabled() {
        compressionFilter.setCompressionEnabled(false);

        MockServerHttpRequest request = MockServerHttpRequest
                .get("/api/test")
                .header("Accept-Encoding", "gzip")
                .build();

        MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();

        compressionFilter.filter(exchange, chain).block();

        assertNull(exchange.getResponse().getHeaders().getFirst("Content-Encoding"));
        verify(chain).filter(any());
    }

    @Test
    void testFilter_OptionsRequest() {
        MockServerHttpRequest request = MockServerHttpRequest
                .method(HttpMethod.OPTIONS, "/api/test")
                .header("Accept-Encoding", "gzip")
                .build();

        MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();

        compressionFilter.filter(exchange, chain).block();

        assertNull(exchange.getResponse().getHeaders().getFirst("Content-Encoding"));
        verify(chain).filter(any());
    }

    @Test
    void testFilter_VaryHeader() {
        MockServerHttpRequest request = MockServerHttpRequest
                .get("/api/test")
                .header("Accept-Encoding", "gzip")
                .build();

        MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();

        compressionFilter.filter(exchange, chain).block();

        assertTrue(exchange.getResponse().getHeaders().get("Vary").contains("Accept-Encoding"));
    }

    @Test
    void testGetOrder() {
        assertEquals(Integer.MAX_VALUE - 100, compressionFilter.getOrder());
    }
}
