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

import cn.novalon.gym.manage.gateway.service.impl.DynamicRouteService;
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.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

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

/**
 * DynamicRouteService单元测试
 * 
 * 文件定义：测试动态路由服务的核心功能
 * 涉及业务：路由增删改查、路由刷新
 * 
 * @author 张翔
 * @date 2026-04-14
 */
@ExtendWith(MockitoExtension.class)
class DynamicRouteServiceTest {

    @Mock
    private RouteDefinitionWriter routeDefinitionWriter;

    @Mock
    private RouteDefinitionLocator routeDefinitionLocator;

    @Mock
    private ApplicationEventPublisher publisher;

    private DynamicRouteService dynamicRouteService;

    @BeforeEach
    void setUp() {
        when(routeDefinitionLocator.getRouteDefinitions())
                .thenReturn(Flux.empty());

        dynamicRouteService = new DynamicRouteService(
                routeDefinitionWriter, 
                routeDefinitionLocator, 
                publisher);
    }

    @Test
    void testAddRoute_Success() {
        RouteDefinition routeDefinition = createRouteDefinition("test-route");

        when(routeDefinitionWriter.save(any())).thenReturn(Mono.empty());

        StepVerifier.create(dynamicRouteService.addRoute(routeDefinition))
                .expectNext(true)
                .verifyComplete();

        verify(routeDefinitionWriter).save(any());
        verify(publisher).publishEvent(any(RefreshRoutesEvent.class));
    }

    @Test
    void testAddRoute_NullRoute() {
        StepVerifier.create(dynamicRouteService.addRoute(null))
                .expectNext(false)
                .verifyComplete();

        verify(routeDefinitionWriter, never()).save(any());
    }

    @Test
    void testDeleteRoute_Success() {
        String routeId = "test-route";
        RouteDefinition routeDefinition = createRouteDefinition(routeId);

        // 先添加路由到缓存中
        when(routeDefinitionWriter.save(any())).thenReturn(Mono.empty());
        StepVerifier.create(dynamicRouteService.addRoute(routeDefinition))
                .expectNext(true)
                .verifyComplete();

        // 然后删除路由
        when(routeDefinitionWriter.delete(any())).thenReturn(Mono.empty());

        StepVerifier.create(dynamicRouteService.deleteRoute(routeId))
                .expectNext(true)
                .verifyComplete();

        verify(routeDefinitionWriter).delete(any());
        verify(publisher, times(2)).publishEvent(any(RefreshRoutesEvent.class));
    }

    @Test
    void testDeleteRoute_NullId() {
        StepVerifier.create(dynamicRouteService.deleteRoute(null))
                .expectNext(false)
                .verifyComplete();

        verify(routeDefinitionWriter, never()).delete(any());
    }

    @Test
    void testGetAllRoutes() {
        RouteDefinition route1 = createRouteDefinition("route1");
        RouteDefinition route2 = createRouteDefinition("route2");

        when(routeDefinitionWriter.save(any())).thenReturn(Mono.empty());

        StepVerifier.create(dynamicRouteService.addRoute(route1))
                .expectNext(true)
                .verifyComplete();

        StepVerifier.create(dynamicRouteService.addRoute(route2))
                .expectNext(true)
                .verifyComplete();

        StepVerifier.create(dynamicRouteService.getRoutes().collectList())
                .assertNext(routes -> {
                    assertNotNull(routes);
                    assertTrue(routes.size() >= 2);
                })
                .verifyComplete();
    }

    @Test
    void testGetRouteCount() {
        RouteDefinition route = createRouteDefinition("test-route");

        when(routeDefinitionWriter.save(any())).thenReturn(Mono.empty());

        StepVerifier.create(dynamicRouteService.addRoute(route))
                .expectNext(true)
                .verifyComplete();

        StepVerifier.create(dynamicRouteService.getRouteCount())
                .assertNext(count -> assertTrue(count >= 1))
                .verifyComplete();
    }

    private RouteDefinition createRouteDefinition(String id) {
        RouteDefinition routeDefinition = new RouteDefinition();
        routeDefinition.setId(id);
        routeDefinition.setUri(java.net.URI.create("http://localhost:8080"));
        return routeDefinition;
    }
}
