package cn.novalon.manage.gateway.cache;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import reactor.test.StepVerifier;

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

@ExtendWith(MockitoExtension.class)
class RequestCacheServiceTest {

    private RequestCacheService cacheService;

    @BeforeEach
    void setUp() {
        cacheService = new RequestCacheService();
    }

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

        StepVerifier.create(cacheService.get(request))
                .verifyComplete();
    }

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

        String response = "{\"data\":\"test\"}";
        cacheService.put(request, response);

        StepVerifier.create(cacheService.get(request))
                .expectNext(response)
                .verifyComplete();
    }

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

        String response = "{\"data\":\"test\"}";
        cacheService.put(request, response);

        cacheService.evict(request);

        StepVerifier.create(cacheService.get(request))
                .verifyComplete();
    }

    @Test
    void testEvictByPattern() {
        ServerHttpRequest request1 = MockServerHttpRequest
                .get("/api/test1")
                .build();
        ServerHttpRequest request2 = MockServerHttpRequest
                .get("/api/test2")
                .build();

        cacheService.put(request1, "response1");
        cacheService.put(request2, "response2");

        cacheService.evictByPattern("GET:/api/test.*");

        assertEquals(0, cacheService.getCacheSize());
    }

    @Test
    void testClear() {
        ServerHttpRequest request1 = MockServerHttpRequest
                .get("/api/test1")
                .build();
        ServerHttpRequest request2 = MockServerHttpRequest
                .get("/api/test2")
                .build();

        cacheService.put(request1, "response1");
        cacheService.put(request2, "response2");

        cacheService.clear();

        assertEquals(0, cacheService.getCacheSize());
    }

    @Test
    void testCacheDisabled() {
        cacheService.setCacheEnabled(false);

        ServerHttpRequest request = MockServerHttpRequest
                .get("/api/test")
                .build();

        cacheService.put(request, "response");

        StepVerifier.create(cacheService.get(request))
                .verifyComplete();

        assertEquals(0, cacheService.getCacheSize());
    }

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

        cacheService.put(request, "response");

        StepVerifier.create(cacheService.get(request))
                .expectNext("response")
                .verifyComplete();

        assertEquals(1, cacheService.getHitCount());
        assertEquals(0, cacheService.getMissCount());
        assertEquals(1.0, cacheService.getHitRate());
    }

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

        StepVerifier.create(cacheService.get(request))
                .verifyComplete();

        assertEquals(0, cacheService.getHitCount());
        assertEquals(1, cacheService.getMissCount());
        assertEquals(0.0, cacheService.getHitRate());
    }

    @Test
    void testMaxCacheSize() {
        cacheService.setMaxCacheSize(5);

        for (int i = 0; i < 10; i++) {
            ServerHttpRequest request = MockServerHttpRequest
                    .get("/api/test" + i)
                    .build();
            cacheService.put(request, "response" + i);
        }

        assertTrue(cacheService.getCacheSize() <= 10);
    }

    @Test
    void testCacheWithQueryParams() {
        ServerHttpRequest request = MockServerHttpRequest
                .get("/api/test?param=value")
                .build();

        String response = "{\"data\":\"test\"}";
        cacheService.put(request, response);

        StepVerifier.create(cacheService.get(request))
                .expectNext(response)
                .verifyComplete();
    }

    @Test
    void testCacheWithDifferentMethods() {
        ServerHttpRequest getRequest = MockServerHttpRequest
                .get("/api/test")
                .build();
        ServerHttpRequest postRequest = MockServerHttpRequest
                .post("/api/test")
                .build();

        cacheService.put(getRequest, "getResponse");
        cacheService.put(postRequest, "postResponse");

        StepVerifier.create(cacheService.get(getRequest))
                .expectNext("getResponse")
                .verifyComplete();

        StepVerifier.create(cacheService.get(postRequest))
                .expectNext("postResponse")
                .verifyComplete();
    }
}
