package click.kamil.springstatemachineexporter.analysis.service;

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

/**
 * Synthetic 1 → 3 → 12 state-machine config hierarchy for cache-correctness tests.
 *
 * <pre>
 * RootAbstractSmConfig
 * ├── BranchAAbstractSmConfig ── BranchA1..4SmConfig
 * ├── BranchBAbstractSmConfig ── BranchB1..4SmConfig
 * └── BranchCAbstractSmConfig ── BranchC1..4SmConfig
 * </pre>
 *
 * <p>Each layer adds one external transition with a unique event name so every concrete
 * config produces a distinct snapshot while sharing the same scanned {@code CodebaseContext}.
 */
final class TwelveConfigHierarchyTestSupport {

    private static final String PKG = "com.example.hierarchy";
    private static final List<String> BRANCHES = List.of("A", "B", "C");

    private TwelveConfigHierarchyTestSupport() {
    }

    static List<String> concreteConfigNames() {
        List<String> names = new ArrayList<>(12);
        for (String branch : BRANCHES) {
            for (int i = 1; i <= 4; i++) {
                names.add("Branch" + branch + i + "SmConfig");
            }
        }
        return names;
    }

    static void writeSources(Path rootDir) throws IOException {
        Files.writeString(rootDir.resolve("RootAbstractSmConfig.java"), rootAbstractSource());
        for (String branch : BRANCHES) {
            Files.writeString(rootDir.resolve("Branch" + branch + "AbstractSmConfig.java"), branchAbstractSource(branch));
            for (int i = 1; i <= 4; i++) {
                Files.writeString(rootDir.resolve("Branch" + branch + i + "SmConfig.java"), concreteSource(branch, i));
            }
        }
    }

    private static String rootAbstractSource() {
        return """
            package %s;
            public abstract class RootAbstractSmConfig extends StateMachineConfigurerAdapter {
                public void configure(StateMachineTransitionConfigurer transitions) throws Exception {
                    transitions.withExternal().source("ROOT_S1").target("ROOT_S2").event("ROOT_E");
                }
            }
            """.formatted(PKG);
    }

    private static String branchAbstractSource(String branch) {
        String event = branchEvent(branch);
        return """
            package %s;
            public abstract class Branch%sAbstractSmConfig extends RootAbstractSmConfig {
                @Override
                public void configure(StateMachineTransitionConfigurer transitions) throws Exception {
                    super.configure(transitions);
                    transitions.withExternal().source("BR_%s_S1").target("BR_%s_S2").event("%s");
                }
            }
            """.formatted(PKG, branch, branch, branch, event);
    }

    private static String concreteSource(String branch, int index) {
        String event = concreteEvent(branch, index);
        String abstractParent = "Branch" + branch + "AbstractSmConfig";
        return """
            package %s;
            public class Branch%s%dSmConfig extends %s {
                @Override
                public void configure(StateMachineTransitionConfigurer transitions) throws Exception {
                    super.configure(transitions);
                    transitions.withExternal().source("C_%s_%d_S1").target("C_%s_%d_S2").event("%s");
                }
            }
            """.formatted(PKG, branch, index, abstractParent, branch, index, branch, index, event);
    }

    static String branchEvent(String branch) {
        return "BRANCH_" + branch + "_E";
    }

    static String concreteEvent(String branch, int index) {
        return "CONCRETE_" + branch + index + "_E";
    }

    static List<String> expectedEventsForConcrete(String branch, int index) {
        return List.of("ROOT_E", branchEvent(branch), concreteEvent(branch, index));
    }
}