package com.infoepoch.pms.dispatchassistant.common.encryption;

import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * AES加密
 */
public class AESTool {

    private static Key key;

    private static String KEY_STR = "supermarket-xjy-2022-09-23";

    private static String KEY_ALGORITHM = "AES";

    private static String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

    static {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            random.setSeed(KEY_STR.getBytes(StandardCharsets.UTF_8));
            kgen.init(128, random);
            key = kgen.generateKey();
            kgen = null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取加密后的字符串
     *
     * @param str
     * @return
     */
    public static String getEncryptString(String str) {
        try {
            if (judgeEncryptFlag(str))
                return str; // 如果字符串已经加密，不会进行二次加密
            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] doFinal = cipher.doFinal(bytes);
            return Base64.getEncoder().encodeToString(doFinal);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取解密后的字符串
     *
     * @param str
     * @return
     */
    public static String getDecryptString(String str) {
        try {
            if (judgeEncryptFlagReverse(str))
                return str;// 如果字符串未加密，返回原字符串
            byte[] bytes = Base64.getDecoder().decode(str);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] doFinal = cipher.doFinal(bytes);
            return new String(doFinal, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 判断是否已加密
     * 原理：加密后的字符串使用Base64编码了，如果进行了编码则是加密后的字符串，否则就是未加密的
     *
     * @param str
     * @return true-已加密 false-未加密
     */
    public static boolean judgeEncryptFlag(String str) {
        if (StringUtils.isBlank(str))
            return true;
        try {
            byte[] bytes = Base64.getDecoder().decode(str);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] doFinal = cipher.doFinal(bytes);
            return doFinal != null;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 判断字符串是否加密（反向标识）
     *
     * @param str
     * @return true-未加密 false-已加密
     */
    public static boolean judgeEncryptFlagReverse(String str) {
        return !judgeEncryptFlag(str);
    }

    public static String encryptWithKey(String keyStr, String str) {
        try {
            if (judgeEncryptWithKey(keyStr, str))
                return str; // 如果字符串已经加密，不会进行二次加密
            Key key = getKey(keyStr);
            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] doFinal = cipher.doFinal(bytes);
            return Base64.getEncoder().encodeToString(doFinal);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String decryptWithKey(String keyStr, String str) {
        try {
//            if (judgeEncryptWithKeyReverse(keyStr, str))
//                return str;// 如果字符串未加密，返回原字符串
            Key key = getKey(keyStr);
//            byte[] bytes = Base64.getDecoder().decode(str);
            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] doFinal = cipher.doFinal(bytes);
            return new String(doFinal, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static boolean judgeEncryptWithKey(String keyStr, String str) {
        if (StringUtils.isBlank(str))
            return true;
        try {
            Key key = getKey(keyStr);
            byte[] bytes = Base64.getDecoder().decode(str);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] doFinal = cipher.doFinal(bytes);
            return doFinal != null;
        } catch (Exception e) {
            return false;
        }
    }

    private static boolean judgeEncryptWithKeyReverse(String keyStr, String str) {
        return !judgeEncryptWithKey(keyStr, str);
    }

    private static Key getKey(String keyStr) {
        Key key;
        try {
            KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            random.setSeed(keyStr.getBytes(StandardCharsets.UTF_8));
            kgen.init(128, random);
            key = kgen.generateKey();
            kgen = null;
            return key;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
