package CipherCracker;

import java.nio.file.Files;
import java.nio.file.Path;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;

public class PrimaryCracker {
    public static ArrayList<Integer> keysArray = new ArrayList<>();
    public static ArrayList<Integer> keyPositionsArray = new ArrayList<>();

    // Switched to IntSequence and made it volatile for safe multithreading publication
    public static volatile HashSet<IntSequence> checkSet = new HashSet<>();

    private static ArrayList<String> getFirst5Words(String text) {
        if (text == null || text.isEmpty()) {
            return null;
        }

        // Split by one or more whitespace characters
        String[] words = text.trim().split("\\s+");
        ArrayList<String> wordArrayList = new ArrayList<>(List.of(words));

        if (wordArrayList.size() > 3) {
            wordArrayList.subList(5, wordArrayList.size()).clear();
        }

        // Join the first x words back together
        return wordArrayList;
    }

    private static void compileFiles(String keyFileName, String checkFileName) {
        try {
            Path keyFilePath = Path.of(keyFileName);
            Path checkFilePath = Path.of(checkFileName);

            // Read everything into a List and Set
            List<String> keysLines = Files.readAllLines(keyFilePath);
            int keysListSize = keysLines.size();
            List<String> checkLines = Files.readAllLines(checkFilePath);

            keysArray.clear();
            keyPositionsArray.clear();

            for (int i = 0; i < keysListSize; i++) {
                String line = keysLines.get(i);
                ArrayList<Integer> convertedLine = ConverterHelpers.primaryIdentifierConverter(line);

                // FIX: Only add the key if it actually contains valid characters!
                if (!convertedLine.isEmpty()) {
                    keyPositionsArray.add(keysArray.size());
                    keysArray.addAll(convertedLine);
                }
            }
            // Create a temporary set so threads don't read a half-finished HashSet
            HashSet<IntSequence> tempSet = new HashSet<>();

            for (String line : checkLines) {
                if (line != null && !line.trim().isEmpty()) {
                    ArrayList<Integer> convertedCheckLine = ConverterHelpers.primaryIdentifierConverter(line);

                    if (!convertedCheckLine.isEmpty()) {
                        // Convert the ArrayList<Integer> into a primitive int[] for maximum speed
                        int[] primitiveArray = new int[convertedCheckLine.size()];
                        for (int j = 0; j < convertedCheckLine.size(); j++) {
                            primitiveArray[j] = convertedCheckLine.get(j); // Line 72
                        }

                        // Add the wrapped primitive array to our fast lookup set
                        tempSet.add(new IntSequence(primitiveArray));
                    }
                }
            }

            // Instantly swap the finished set into the volatile reference for the threads
            checkSet = tempSet;

        } catch (IOException e) {
            System.err.println("An error occurred while reading the file: " + e.getMessage());
        }
    }

    public static String cracker(String checkFileName, String keyFileName, String cipherText) {
        if (cipherText == null || cipherText.isEmpty()) {
            System.err.println("No cipher text provided.");
            return checkFileName;
        }

        // The first 3 words optimization
        ArrayList<String> first5Words = getFirst5Words(cipherText);

        if (first5Words != null) {

            // Assuming compileFiles() has already been called to populate checkSet and keysArray.
            compileFiles(keyFileName, checkFileName);

            return ConverterHelpers.reversePrimaryIdentifierConverter(ThreadManager.manager(checkSet, keysArray, keyPositionsArray, first5Words));

        }
        return checkFileName;
    }
}