import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.StructuredTaskScope;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;

public class TestJoinUntil {
    static final Scanner scanner = new Scanner(System.in);
    static final AtomicLong counter = new AtomicLong(0);
    static final String RESUME_STRING = "0";
    static final List<Integer> STEPS = List.of(
            1,
            10,
            100,
            1_000,
            10_000,
            100_000,
            1_000_000,
            10_000_000,
            20_000_000,
            30_000_000,
            31_000_000,
            32_000_000,
            33_000_000,
            34_000_000,
            35_000_000,
            36_000_000,
            37_000_000,
            38_000_000,
            39_000_000,
            40_000_000,
            50_000_000,
            60_000_000,
            70_000_000
    );

    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        Duration duration;
        for (int currentConcurrency : STEPS) {
            try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
                for (int i = 0; i < currentConcurrency; i++) {
                    scope.fork(TestJoinUntil::incCount);
                }

                Instant startTime = Instant.now();
                scope.joinUntil(startTime.plusSeconds(10));
                scope.throwIfFailed();
                Instant endTime = Instant.now();
                duration = Duration.between(startTime, endTime);
            }
            long counterValue = counter.get();
            System.out.printf("%d.%06d seconds. Concurrency=%d.%s Enter %s to resume: ",
                    duration.getSeconds(),
                    duration.getNano() / 1_000,
                    currentConcurrency,
                    (counterValue == currentConcurrency) ? "" : "Counter=" + counterValue + " (" + (currentConcurrency - counterValue) + " tasks were failed). ",
                    RESUME_STRING);

            if (! scanner.nextLine().equals(RESUME_STRING)) {
                break;
            }
            counter.set(0);
        }
    }

    public static long incCount() {
        return counter.incrementAndGet();
    }
}