import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class DeterminantCalculator {
    public static int calculateDeterminant(int[][] matrix, int numThreads) throws InterruptedException, ExecutionException {
        int size = matrix.length;

        // Если размер матрицы 1x1, возвращаем единственный элемент.
        if (size == 1) {
            return matrix[0][0];
        }

        // Если количество потоков равно 1, выполняем последовательный алгоритм.
        if (numThreads == 1) {
            return sequentialDeterminant(matrix);
        }

        // Иначе выполняем параллельный алгоритм.
        return parallelDeterminant(matrix, numThreads);
    }

    private static int sequentialDeterminant(int[][] matrix) {
        int size = matrix.length;
        if (size == 1) {
            return matrix[0][0];
        }
        if (size == 2) {
            return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
        }

        int determinant = 0;
        for (int col = 0; col < size; col++) {
            determinant += (int) (Math.pow(-1, col) * matrix[0][col] * sequentialDeterminant(getMinor(matrix, 0, col)));
        }
        return determinant;
    }

    private static int parallelDeterminant(int[][] matrix, int numThreads) throws InterruptedException, ExecutionException {
        int size = matrix.length;
        ExecutorService executor = Executors.newFixedThreadPool(numThreads);
        List<Future<Double>> futures = new ArrayList<>();

        for (int col = 0; col < size; col++) {
            int finalCol = col;
            futures.add(executor.submit(() -> {
                double minorDet = sequentialDeterminant(getMinor(matrix, 0, finalCol));
                return Math.pow(-1, finalCol) * matrix[0][finalCol] * minorDet;
            }));
        }

        int determinant = 0;
        for (Future<Double> future : futures) {
            determinant += future.get();
        }

        executor.shutdown();
        return determinant;
    }

    private static int[][] getMinor(int[][] matrix, int row, int col) {
        int size = matrix.length;
        int[][] minor = new int[size - 1][size - 1];

        for (int i = 0, mi = 0; i < size; i++) {
            if (i == row) continue;
            for (int j = 0, mj = 0; j < size; j++) {
                if (j == col) continue;
                minor[mi][mj] = matrix[i][j];
                mj++;
            }
            mi++;
        }
        return minor;
    }
}