package click.kamil.springstatemachineexporter.analysis.service;

import click.kamil.springstatemachineexporter.exporter.JsonExporter;
import click.kamil.springstatemachineexporter.service.ExportService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
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 java.util.stream.StreamSupport;

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

/**
 * Export-level gate for {@code state_machines/jms_abstract_template_sample}: abstract
 * {@code @JmsListener} must produce JMS callChains through concrete subclass hooks.
 */
class JmsAbstractTemplateSampleExportTest {

    @Test
    void exportShouldProduceJmsCallChainsThroughConcreteSubclassHooks(@TempDir Path tempDir) throws Exception {
        Path root = findProjectRoot();
        Path sample = root.resolve("state_machines/jms_abstract_template_sample");
        assertThat(sample).isDirectory();

        Path outputDir = tempDir.resolve("out");
        ExportService exportService = new ExportService(List.of(new JsonExporter()));
        exportService.runExporter(
                sample,
                outputDir,
                List.of("json"),
                true,
                List.of(),
                null,
                null,
                click.kamil.springstatemachineexporter.exporter.EnumFormat.fn,
                click.kamil.springstatemachineexporter.exporter.EnumFormat.fn);

        Path jsonFile = Files.walk(outputDir)
                .filter(path -> path.getFileName().toString().endsWith(".json"))
                .findFirst()
                .orElseThrow();

        JsonNode rootJson = new ObjectMapper().readTree(jsonFile.toFile());
        List<JsonNode> callChains = StreamSupport.stream(
                        rootJson.path("metadata").path("callChains").spliterator(), false)
                .toList();

        assertThat(callChains)
                .as("abstract JMS template sample must export at least one callChain")
                .isNotEmpty();

        assertThat(callChains)
                .anySatisfy(chain -> {
                    String entry = chain.path("entryPoint").path("name").asText();
                    assertThat(entry).containsIgnoringCase("JMS");
                    String methods = chain.path("methodChain").toString();
                    assertThat(methods).containsAnyOf("OrderAA", "DocumentAA", "AbstractAA", "sendEvent");
                });

        assertThat(callChains.stream()
                .filter(chain -> chain.path("methodChain").toString().contains("OrderAA"))
                .toList())
                .allSatisfy(chain -> assertThat(chain.path("methodChain").toString())
                        .doesNotContain("DocumentAA.doPMessage"));
    }

    private static Path findProjectRoot() {
        Path current = Path.of(".").toAbsolutePath().normalize();
        while (current != null && !Files.exists(current.resolve("settings.gradle"))) {
            current = current.getParent();
        }
        if (current == null) {
            throw new IllegalStateException("Could not find project root");
        }
        return current;
    }
}
