package click.kamil.springstatemachineexporter.analysis.service;

import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class SpringMvcDetectorTest {

    @Test
    void shouldDetectWebFluxRouterFunctionBean(@TempDir Path tempDir) throws Exception {
        String source = """
            package com.example;
            import org.springframework.context.annotation.Bean;
            import org.springframework.context.annotation.Configuration;
            import org.springframework.web.reactive.function.server.RouterFunction;
            import org.springframework.web.reactive.function.server.ServerResponse;
            import static org.springframework.web.reactive.function.server.RouterFunctions.route;
            @Configuration
            public class ReactiveOrderApi {
                @Bean
                public RouterFunction<ServerResponse> orderRoutes() {
                    return route().POST("/reactive/order", request -> ServerResponse.ok().build()).build();
                }
            }
            """;
        Files.writeString(tempDir.resolve("ReactiveOrderApi.java"), source);

        CodebaseContext context = new CodebaseContext();
        context.setResolveBindings(true);
        context.scan(tempDir);

        SpringMvcDetector detector = new SpringMvcDetector(context, context.getConstantResolver());
        org.eclipse.jdt.core.dom.TypeDeclaration td = context.getTypeDeclaration("com.example.ReactiveOrderApi");
        List<EntryPoint> entryPoints = detector.detect((org.eclipse.jdt.core.dom.CompilationUnit) td.getRoot());

        assertThat(entryPoints).anyMatch(ep ->
                "POST /reactive/order".equals(ep.getName())
                        && "orderRoutes".equals(ep.getMethodName())
                        && "WebFlux Functional".equals(ep.getMetadata().get("style")));
    }

    @Test
    void shouldDetectRestControllerPostMapping(@TempDir Path tempDir) throws Exception {
        String source = """
            package com.example;
            import org.springframework.web.bind.annotation.*;
            @RestController
            @RequestMapping("/api/orders")
            public class OrderController {
                @PostMapping("/pay")
                public void pay() {}
            }
            """;
        Files.writeString(tempDir.resolve("OrderController.java"), source);

        CodebaseContext context = new CodebaseContext();
        context.setResolveBindings(true);
        context.scan(tempDir);

        SpringMvcDetector detector = new SpringMvcDetector(context, context.getConstantResolver());
        org.eclipse.jdt.core.dom.TypeDeclaration td = context.getTypeDeclaration("com.example.OrderController");
        List<EntryPoint> entryPoints = detector.detect((org.eclipse.jdt.core.dom.CompilationUnit) td.getRoot());

        assertThat(entryPoints).anyMatch(ep ->
                "POST /api/orders/pay".equals(ep.getName()) && "pay".equals(ep.getMethodName()));
    }

    @Test
    void shouldDetectInterfaceMappedRestEndpointOnImplOnly(@TempDir Path tempDir) throws Exception {
        String apiSource = """
            package com.example;
            import org.springframework.web.bind.annotation.*;
            @RequestMapping("/api/v2/orders")
            public interface OrderApi {
                @PostMapping("/submit")
                void submitOrder();
            }
            """;
        String implSource = """
            package com.example;
            import org.springframework.web.bind.annotation.RestController;
            @RestController
            public class OrderControllerImpl implements OrderApi {
                @Override
                public void submitOrder() {}
            }
            """;
        Files.writeString(tempDir.resolve("OrderApi.java"), apiSource);
        Files.writeString(tempDir.resolve("OrderControllerImpl.java"), implSource);

        CodebaseContext context = new CodebaseContext();
        context.setResolveBindings(true);
        context.scan(tempDir);

        SpringMvcDetector detector = new SpringMvcDetector(context, context.getConstantResolver());
        org.eclipse.jdt.core.dom.TypeDeclaration impl = context.getTypeDeclaration("com.example.OrderControllerImpl");
        List<EntryPoint> entryPoints = detector.detect((org.eclipse.jdt.core.dom.CompilationUnit) impl.getRoot());

        assertThat(entryPoints).hasSize(1);
        assertThat(entryPoints.get(0).getName()).isEqualTo("POST /api/v2/orders/submit");
        assertThat(entryPoints.get(0).getClassName()).isEqualTo("com.example.OrderControllerImpl");
    }
}
