package click.kamil.springstatemachineexporter.analysis.service;

import click.kamil.springstatemachineexporter.analysis.model.CallEdge;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.*;

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

class CallGraphPathFinderTest {

    private CallGraphPathFinder pathFinder;

    @BeforeEach
    void setUp() {
        pathFinder = new CallGraphPathFinder(new CodebaseContext());
    }

    @Test
    void shouldSkipFrameworkAndJdkPaths() {
        Map<String, List<CallEdge>> graph = new HashMap<>();

        // Setup an anonymized call graph where business logic delegates to a platform boundary
        // e.g. BusinessService.process -> java.util.stream.Stream.map -> AnotherBusinessService.doWork
        // The pathfinder should skip the java.* path, avoiding spurious hops.
        
        graph.put("com.acme.BusinessService.process", List.of(
                new CallEdge("java.util.stream.Stream.map", List.of()),
                new CallEdge("com.acme.DirectService.execute", List.of())
        ));
        graph.put("java.util.stream.Stream.map", List.of(
                new CallEdge("com.acme.AnotherBusinessService.doWork", List.of())
        ));
        graph.put("com.acme.DirectService.execute", List.of(
                new CallEdge("com.acme.AnotherBusinessService.doWork", List.of())
        ));

        List<List<String>> paths = pathFinder.findAllPaths(
                "com.acme.BusinessService.process",
                "com.acme.AnotherBusinessService.doWork",
                graph,
                new HashSet<>()
        );

        // It should ONLY find the direct business path, skipping the java.util path.
        assertThat(paths).hasSize(1);
        assertThat(paths.get(0)).containsExactly(
                "com.acme.BusinessService.process",
                "com.acme.DirectService.execute",
                "com.acme.AnotherBusinessService.doWork"
        );
    }

    @Test
    void shouldFollowValidBusinessPaths() {
        Map<String, List<CallEdge>> graph = new HashMap<>();

        graph.put("com.acme.Start.run", List.of(
                new CallEdge("com.acme.Middle.process", List.of())
        ));
        graph.put("com.acme.Middle.process", List.of(
                new CallEdge("com.acme.End.finish", List.of())
        ));

        List<List<String>> paths = pathFinder.findAllPaths(
                "com.acme.Start.run",
                "com.acme.End.finish",
                graph,
                new HashSet<>()
        );

        assertThat(paths).hasSize(1);
        assertThat(paths.get(0)).containsExactly(
                "com.acme.Start.run",
                "com.acme.Middle.process",
                "com.acme.End.finish"
        );
    }
}
