// Path: neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/utils/Neo4jContainerUtils.java
// public static Neo4jContainer<?> createNeo4jContainer() {
//     return new Neo4jContainer<>(neo4jImageCoordinates()).withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes")
//             .waitingFor(boltStart())
//             .withAdminPassword(null);
// }


import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.Session;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.containers.wait.strategy.WaitStrategy;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static org.neo4j.jdbc.bolt.utils.Neo4jContainerUtils.createNeo4jContainer;
        Function<GenericContainer<?>, String> getProxyUrl = instance ->
                String.format("%s:%d", instance.getContainerIpAddress(), instance.getMappedPort(DEFAULT_BOLT_PORT));
        return iterateMembers(numberOfCoreMembers, instanceType)
                .map(name -> getNeo4jContainer(waitForBolt, network, initialDiscoveryMembers, sidecars, getProxyUrl, instanceType, neo4jConfig, name))
                .collect(toList());
    }

    private static Map<String, GenericContainer<?>> createSidecars(int numOfMembers, Network network, ClusterInstanceType instanceType) {
        return iterateMembers(numOfMembers, instanceType)
                .collect(toMap(
                        Function.identity(),
                        name -> new GenericContainer<>("alpine/socat")
                                .withNetwork(network)
                                .withLabel("memberType", instanceType.toString())
                                // Expose the default bolt port on the sidecar
                                .withExposedPorts(DEFAULT_BOLT_PORT)
                                // And redirect that port to the corresponding Neo4j instance
                                .withCommand(String
                                        .format("tcp-listen:%d,fork,reuseaddr tcp-connect:%s:%1$d", DEFAULT_BOLT_PORT, name))
                ));
    }

    private static Neo4jContainer<?> getNeo4jContainer(WaitStrategy waitForBolt,
                                                                      Network network,
                                                                      String initialDiscoveryMembers,
                                                                      Map<String, GenericContainer<?>> sidecars,
                                                                      Function<GenericContainer<?>, String> getProxyUrl,
                                                                      ClusterInstanceType instanceType,
                                                                      Map<String, Object> neo4jConfig,
                                                                      String name) {
// Path: neo4j-jdbc-bolt/src/test/java/org/neo4j/jdbc/bolt/utils/Neo4jContainerUtils.java
// public static Neo4jContainer<?> createNeo4jContainer() {
//     return new Neo4jContainer<>(neo4jImageCoordinates()).withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes")
//             .waitingFor(boltStart())
//             .withAdminPassword(null);
// }


// Path: neo4j-jdbc-bolt/src/test/java/org/neo4j/TestcontainersCausalCluster.java
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.Session;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.containers.wait.strategy.WaitStrategy;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static org.neo4j.jdbc.bolt.utils.Neo4jContainerUtils.createNeo4jContainer;

        Function<GenericContainer<?>, String> getProxyUrl = instance ->
                String.format("%s:%d", instance.getContainerIpAddress(), instance.getMappedPort(DEFAULT_BOLT_PORT));
        return iterateMembers(numberOfCoreMembers, instanceType)
                .map(name -> getNeo4jContainer(waitForBolt, network, initialDiscoveryMembers, sidecars, getProxyUrl, instanceType, neo4jConfig, name))
                .collect(toList());
    }

    private static Map<String, GenericContainer<?>> createSidecars(int numOfMembers, Network network, ClusterInstanceType instanceType) {
        return iterateMembers(numOfMembers, instanceType)
                .collect(toMap(
                        Function.identity(),
                        name -> new GenericContainer<>("alpine/socat")
                                .withNetwork(network)
                                .withLabel("memberType", instanceType.toString())
                                // Expose the default bolt port on the sidecar
                                .withExposedPorts(DEFAULT_BOLT_PORT)
                                // And redirect that port to the corresponding Neo4j instance
                                .withCommand(String
                                        .format("tcp-listen:%d,fork,reuseaddr tcp-connect:%s:%1$d", DEFAULT_BOLT_PORT, name))
                ));
    }

    private static Neo4jContainer<?> getNeo4jContainer(WaitStrategy waitForBolt,
                                                                      Network network,
                                                                      String initialDiscoveryMembers,
                                                                      Map<String, GenericContainer<?>> sidecars,
                                                                      Function<GenericContainer<?>, String> getProxyUrl,
                                                                      ClusterInstanceType instanceType,
                                                                      Map<String, Object> neo4jConfig,
                                                                      String name) {
        Neo4jContainer<?> container = createNeo4jContainer()