package tech.nevets.jaml.util;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.Random;

public class Encryptor {

    public static DataCompressor encrypt(String textToEncrypt) {
        String key = generateHash();
        String salt = generateHash();
        String hashedData = null;

        try {
            byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            KeySpec spec = new PBEKeySpec(key.toCharArray(), salt.getBytes(), 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
            hashedData = Base64.getEncoder().encodeToString(cipher.doFinal(textToEncrypt.getBytes(StandardCharsets.UTF_8)));

        } catch (Exception e) {
            System.out.println("Error while encrypting: " + e.getMessage());
        }

        DataCompressor pair = new DataCompressor(hashedData, key, salt);

        return pair;
    }

    public static String decrypt(DataCompressor pair) {
        String hash = pair.getData();
        String key = pair.getKey();
        String salt = pair.getSalt();
        String password = null;

        try {
            byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            KeySpec spec = new PBEKeySpec(key.toCharArray(), salt.getBytes(), 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec);
            password = new String(cipher.doFinal(Base64.getDecoder().decode(hash)));

        } catch (Exception e) {
            System.out.println("Error while decrypting: " + e.getMessage());
        }

        return password;
    }

    public static String generateHash(){
        String[] chars = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "!", "@", "#", "$", "%", "&"};
        Random rand = new Random();
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < 64; i++) {
            sb.append(chars[rand.nextInt(chars.length)]);
        }

        return sb.toString();
    }
}
