package com.iqser.red.service.peristence.v1.server.integration.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;

@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class MultithreadedTestRunner {

    int numberOfThreads;
    int numberOfExecutions;


    public List<Exception> runMutlithreadedCollectingExceptions(boolean stopOnFirstRunWithExceptions, Runnable test, Runnable afterTest) {

        List<Exception> allExceptions = new ArrayList<>();

        for (int execution = 1; execution <= numberOfExecutions; execution++) {
            var threads = new ArrayList<Thread>(numberOfThreads);
            var exceptions = Collections.synchronizedList(new ArrayList<Exception>());

            for (int threadNumber = 1; threadNumber <= numberOfThreads; threadNumber++) {
                Thread t = new Thread(() -> {
                    try {
                        test.run();
                    } catch (Exception e) {
                        exceptions.add(e);
                    }
                });

                threads.add(t);
            }

            for (Thread t : threads) {
                t.start();
            }

            for (Thread t : threads) {
                try {
                    t.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            afterTest.run();

            if (stopOnFirstRunWithExceptions) {
                if (!exceptions.isEmpty()) {
                    return exceptions;
                }
            } else {
                allExceptions.addAll(exceptions);
            }
        }

        return allExceptions;
    }


    public List<Exception> runMutlithreadedCollectingExceptions(Runnable test, Runnable afterTest) {

        return runMutlithreadedCollectingExceptions(true, test, afterTest);
    }

}
