// Exercise 2: ExecutorService, Future, and collecting async results (medium/hard)
//
// Implement:
//   - sumOfSquaresAsync(nums, pool): submit ONE task PER NUMBER to `pool`,
//     each task computing that number's square, collect all the resulting
//     Future<Integer> handles, then sum their results (via .get(), which
//     blocks until each task is done) and return the total.
//
// Must submit one task per element (not compute everything on the calling
// thread) so the self-check can prove real submission happened by counting
// how many distinct threads actually ran a task.

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class java_concurrency_basics_exercise_2 {

    static int sumOfSquaresAsync(List<Integer> nums, ExecutorService pool) throws Exception {
        // TODO: for each n in nums, pool.submit(() -> n * n) and collect the
        // Future<Integer> into a List; then sum every future.get() and return it.
        return 0;
    }

    // --- self-check: do not modify below this line ---
    public static void main(String[] args) throws Exception {
        boolean ok = true;

        ExecutorService pool = Executors.newFixedThreadPool(4);
        Set<String> threadNamesUsed = ConcurrentHashMap.newKeySet();

        List<Integer> nums = List.of(1, 2, 3, 4, 5);
        int result = sumOfSquaresAsync(nums, pool);
        ok &= result == 55; // 1+4+9+16+25

        int emptyResult = sumOfSquaresAsync(List.of(), pool);
        ok &= emptyResult == 0;

        // Instrumented run: submit tasks that record their executing thread's
        // name, proving tasks actually ran on POOLED threads, not the main thread.
        List<Future<?>> futures = new ArrayList<>();
        for (int i = 0; i < 8; i++) {
            futures.add(pool.submit(() -> threadNamesUsed.add(Thread.currentThread().getName())));
        }
        for (Future<?> f : futures) f.get();
        ok &= !threadNamesUsed.contains(Thread.currentThread().getName()); // main thread never ran a pooled task
        ok &= threadNamesUsed.size() >= 1 && threadNamesUsed.size() <= 4; // bounded by pool size (4)

        pool.shutdown();

        System.out.println(ok ? "PASS" : "FAIL");
    }
}
