package top.r3944realms.lib39.core.lang;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

/**
 * The type Class encryptor.
 */
public class ClassEncryptor {
    static {
        System.loadLibrary("ClassEncrypt");
    }

    /**
     * Encrypt class byte [ ].
     *
     * @param classData the class data
     * @param key       the key
     * @return the byte [ ]
     */
    public native byte[] encryptClass(byte[] classData, String key);

    /**
     * Decrypt class byte [ ].
     *
     * @param encryptedData the encrypted data
     * @param key           the key
     * @return the byte [ ]
     */
    public native byte[] decryptClass(byte[] encryptedData, String key);

    /**
     * Is encrypted file boolean.
     *
     * @param fileData the file data
     * @return the boolean
     */
    public native boolean isEncryptedFile(byte[] fileData);

    /**
     * Encrypt class file.
     *
     * @param inputPath  the input path
     * @param outputPath the output path
     * @param key        the key
     * @throws IOException the io exception
     */
    public void encryptClassFile(String inputPath, String outputPath, String key)
            throws IOException {
        byte[] classData = Files.readAllBytes(Paths.get(inputPath));
        byte[] encryptedData = encryptClass(classData, key);
        Files.write(Paths.get(outputPath), encryptedData);
        System.out.println("Encrypted: " + inputPath + " -> " + outputPath);
    }


    /**
     * Encrypt directory.
     *
     * @param inputDir  the input dir
     * @param outputDir the output dir
     * @param key       the key
     * @throws IOException the io exception
     */
    public void encryptDirectory(String inputDir, String outputDir, String key)
            throws IOException {
        try (Stream<Path> walk = Files.walk(Paths.get(inputDir))) {
            walk
                    .filter(Files::isRegularFile)
                    .filter(p -> p.toString().endsWith(".class"))
                    .forEach(p -> {
                        try {
                            String relativePath = inputDir.equals(p.getParent().toString())
                                    ? p.getFileName().toString()
                                    : inputDir.equals(p.getParent().getParent().toString())
                                    ? p.getParent().getFileName() + "/" + p.getFileName()
                                    : p.toString().substring(inputDir.length() + 1);

                            Path outputPath = Paths.get(outputDir, relativePath);
                            Files.createDirectories(outputPath.getParent());

                            encryptClassFile(p.toString(), outputPath.toString(), key);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
        }
    }
}
