package com.crm.rely.backend.util;

import com.crm.rely.backend.core.constant.Constants;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;

public class AESUtil {
    private static final String KEY_ALGORITHM = "AES";

    private static final String KEY_GCM_NO_PADDING_ALGORITHM = "AES/GCM/NoPadding";

    private static final String SHA1PRNG = "SHA1PRNG";
    private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();

    /**
     * AES 加密操作
     *
     * @param content 待加密内容
     * @return 返回Base64转码后的加密数据
     */
    public static String encrypt(String content) {
        return AESUtil.encrypt(content, Constants.AES_KEY);
    }

    public static String encrypt(String content, String secureKey) {

        return AESUtil.encrypt(content, secureKey, AESUtil.KEY_ALGORITHM);
    }

    public static String encrypt(String content, String secureKey, String algorithm) {

        return AESUtil.encrypt(content, secureKey, algorithm, AESUtil.SHA1PRNG);
    }

    public static String encrypt(String content, String secureKey, String algorithm, String srAlgorithm) {
        try {
            if ((StringUtils.isEmpty(content)) ||
                    (StringUtils.isEmpty(secureKey))) {
                return null;
            }
            KeyGenerator kgen = KeyGenerator.getInstance(algorithm);

            SecureRandom secureRandom = SecureRandom.getInstance(srAlgorithm);
            secureRandom.setSeed(secureKey.getBytes());
            kgen.init(128, secureRandom);
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, algorithm);
            Cipher cipher = Cipher.getInstance(algorithm);
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(1, key);
            byte[] result = cipher.doFinal(byteContent);
            return AESUtil.encodeBASE64(result);
        } catch (Exception ex) {
//            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public static String decrypt(String content, String secureKey) {

        return AESUtil.decrypt(content, secureKey, AESUtil.KEY_ALGORITHM);
    }

    public static String decrypt(String content, String secureKey, String algorithm) {

        return AESUtil.decrypt(content, secureKey, algorithm, AESUtil.SHA1PRNG);
    }

    public static String decrypt(String content, String secureKey, String algorithm, String srAlgorithm) {
        try {
            if ((StringUtils.isEmpty(content)) || (StringUtils.isEmpty(secureKey))) {
                return null;
            }
            KeyGenerator kgen = KeyGenerator.getInstance(algorithm);
            SecureRandom secureRandom = SecureRandom.getInstance(srAlgorithm);
            secureRandom.setSeed(secureKey.getBytes());
            kgen.init(128, secureRandom);
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, algorithm);
            Cipher cipher = Cipher.getInstance(algorithm);
            cipher.init(2, key);
            byte[] base64Dec = Base64.decode(content);
            byte[] result = cipher.doFinal(base64Dec);
            return new String(result);
        } catch (Exception ex) {
//            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    /**
     * AES 解密操作
     *
     * @param content
     * @return
     */
    public static String decrypt(String content) {
        return AESUtil.decrypt(content, Constants.AES_KEY);
    }

    public static String encodeBASE64(byte[] content)
            throws Exception {
        if ((content == null) || (content.length == 0)) {
            return null;
        }
        try {
            return Base64.encode(content);
        } catch (Exception ex) {
//            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public static String encryptPayload(String payload, String key) throws Exception {
        SecureRandom r = new SecureRandom();

        byte[] ivBytes = new byte[16];
        r.nextBytes(ivBytes);

        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
        byte[] inputBytes = payload.getBytes(StandardCharsets.UTF_8);
        byte[] encryptedBytes = AESUtil.encryptDataWithAes(inputBytes, keyBytes, ivBytes);

        byte[] cipherTextBytes = Arrays.copyOfRange(encryptedBytes, 0, payload.length());
        byte[] authTagBytes = Arrays.copyOfRange(encryptedBytes, payload.length(), encryptedBytes.length);

        String ivHex = AESUtil.bytesToHex(ivBytes);
        String encryptedHex = AESUtil.bytesToHex(cipherTextBytes);
        String authTagHex = AESUtil.bytesToHex(authTagBytes);

        String result = new StringBuilder()
                .append(ivHex)
                .append(":")
                .append(encryptedHex)
                .append(":")
                .append(authTagHex)
                .toString();
        return result;
    }

    private static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = AESUtil.HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = AESUtil.HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }

    private static byte[] encryptDataWithAes(byte[] plainText, byte[] aesKey, byte[] aesIv) throws Exception {
        GCMParameterSpec gcmSpec = new GCMParameterSpec(128, aesIv);
        Cipher cipher = Cipher.getInstance(AESUtil.KEY_GCM_NO_PADDING_ALGORITHM);
        SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, AESUtil.KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmSpec);
        byte[] cipherText = cipher.doFinal(plainText);

        return cipherText;
    }

    public static void main(String[] args) throws Exception {
//        String content = "hello,您好";
//
//        System.out.println("content:" + content);
//        String s1 = AESUtil.encrypt(content, Constants.AES_KEY);
//        System.out.println("s1:" + s1);
//        System.out.println("s2:" + AESUtil.decrypt(s1, Constants.AES_KEY));
//        System.out.println(encrypt("b36232e2356b4f549d8ba65ec203b075!@#WEB"));
//        System.out.println(decrypt("SDHmpqX6SSMKYLEpeUu9ivYd0CLJfcMRqn5cmL1X3WsP2WtHK7Fw3Fma82SSEs3b"));


//        String customId = "20926";
//        String en = encrypt(customId);
//        System.out.println(en);
//        System.out.println(decrypt(en));
//        System.out.println(AESUtil.encrypt("123", "gvwt4pujpR5atJueUAFBTiM5Con3obhE"));
//        System.out.println(AESUtil.encrypt("123", "gvwt4pujpR5atJueUAFBTiM5Con3obhE",
//                AESUtil.KEY_ALGORITHM, AESUtil.SHA1PRNG));
//        System.out.println(AESUtil.encrypt("123", "gvwt4pujpR5atJueUAFBTiM5Con3obhE"));
//        System.out.println(AESUtil.encryptPayload("123", "gvwt4pujpR5atJueUAFBTiM5Con3obhE"));
//        System.out.println(AESUtil.getSha512Hash("1,0,10"));

    }

}
