package click.kamil.springstatemachineexporter.service;

import click.kamil.springstatemachineexporter.exporter.JsonExporter;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

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

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

class ExportServiceInlineAccessorsTest {

    @Test
    void shouldSkipAccessorIndexWhenInlineAccessorsDisabled(@TempDir Path tempDir) throws IOException {
        Path sourceRoot = tempDir.resolve("project");
        writeJava(sourceRoot, "com/example/Payload.java", """
                package com.example;
                public class Payload {
                    private String event = "PAY";
                    public String getEvent() { return event; }
                }
                """);
        writeJava(sourceRoot, "com/example/Config.java", """
                package com.example;
                import org.springframework.context.annotation.Configuration;
                import org.springframework.statemachine.config.EnableStateMachine;
                import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
                import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
                import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
                
                @Configuration
                @EnableStateMachine
                public class Config extends StateMachineConfigurerAdapter<String, String> {
                    @Override
                    public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
                        states.withStates().initial("NEW").state("PAID");
                    }
                    @Override
                    public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
                        transitions.withExternal().source("NEW").target("PAID").event("PAY");
                    }
                }
                """);

        CodebaseContext enabledContext = scanContext(sourceRoot, true);
        assertThat(enabledContext.getAccessorIndex().trivialCount()).isGreaterThan(0);

        CodebaseContext disabledContext = scanContext(sourceRoot, false);
        assertThat(disabledContext.getAccessorIndex().trivialCount()).isZero();
    }

    @Test
    void shouldExportWithInlineAccessorsFlag(@TempDir Path inputDir, @TempDir Path outputDir) throws IOException {
        writeJava(inputDir, "com/example/SimpleConfig.java", """
                package com.example;
                import org.springframework.context.annotation.Configuration;
                import org.springframework.statemachine.config.EnableStateMachine;
                import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
                import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
                import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
                
                @Configuration
                @EnableStateMachine
                public class SimpleConfig extends StateMachineConfigurerAdapter<String, String> {
                    @Override
                    public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
                        states.withStates().initial("A").state("B");
                    }
                    @Override
                    public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
                        transitions.withExternal().source("A").target("B").event("GO");
                    }
                }
                """);

        ExportService exportService = new ExportService(List.of(new JsonExporter()));
        exportService.runExporter(inputDir, outputDir, List.of("json"), true, List.of(), null, null,
                click.kamil.springstatemachineexporter.exporter.EnumFormat.fn,
                click.kamil.springstatemachineexporter.exporter.EnumFormat.fn,
                true,
                false);

        try (var stream = Files.list(outputDir)) {
            assertThat(stream.filter(Files::isDirectory).count()).isGreaterThan(0);
        }
    }

    private static CodebaseContext scanContext(Path sourceRoot, boolean inlineAccessors) throws IOException {
        CodebaseContext context = new CodebaseContext();
        context.setResolveBindings(true);
        context.setSourcepath(List.of(sourceRoot.toAbsolutePath().toString()));
        context.setInlineAccessors(inlineAccessors);
        context.scan(sourceRoot);
        return context;
    }

    private static void writeJava(Path root, String relativePath, String source) throws IOException {
        Path file = root.resolve(relativePath);
        Files.createDirectories(file.getParent());
        Files.writeString(file, source);
    }
}
