package com.zkjc.common.utils;

import android.text.TextUtils;

import androidx.annotation.Nullable;

import com.alibaba.fastjson.JSONObject;
import com.zkjc.commons.codec.Charsets;
import com.zkjc.commons.codec.binary.Base64;
import com.zkjc.commons.codec.binary.StringUtils;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import io.reactivex.exceptions.Exceptions;

/**
 * AES 工具类
 *
 * @author zhouhao
 */
public class AesEncryptUtil {
    //可配置到Constant中，并读取配置文件注入,16位,自己定义
    private static final String KEY = "2SexR1rfjZ8CD3M6";

    //参数分别代表 算法名称/加密模式/数据填充方式
    private static final String ALGORITHMSTR = "AES/CBC/NoPadding";

    /**
     * 加密
     *
     * @param content    加密的字符串
     * @param encryptKey key值
     * @return
     * @throws Exception
     */
    public static String encrypt(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
        byte[] b = cipher.doFinal(content.getBytes("utf-8"));
        // 采用base64算法进行转码,避免出现中文乱码
        return Base64.encodeBase64String(b);

    }

    /**
     * 编码
     */
    private static final String ENCODING = "UTF-8";
    /**
     * 算法定义
     */
    private static final String AES_ALGORITHM = "AES";
    /**
     * 指定填充方式
     */
    private static final String CIPHER_PADDING = "AES/ECB/PKCS5Padding";
    private static final String CIPHER_CBC_PADDING = "AES/CBC/PKCS5Padding";
    /**
     * 偏移量(CBC中使用，增强加密算法强度)
     */
    private static final String IV_SEED = "4931232589415761";

    public static String encryptWth(String content) {
        String aesKey = "2SexR1rfjZ8CD3M6";
        if (TextUtils.isEmpty(content)) {
            return "AES encrypt: the content is null!";
        }
        //判断秘钥是否为16位
        if (!TextUtils.isEmpty(aesKey) && aesKey.length() == 16) {
            try {
                //对密码进行编码
                byte[] bytes = aesKey.getBytes(ENCODING);
                //设置加密算法，生成秘钥
                SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);
                // "算法/模式/补码方式"
                Cipher cipher = Cipher.getInstance(CIPHER_PADDING);
                //选择加密
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
                //根据待加密内容生成字节数组
                byte[] encrypted = cipher.doFinal(content.getBytes(ENCODING));
                //返回base64字符串
                return Base64.encodeBase64String(encrypted);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            return "AES encrypt: the aesKey is null or error!";
        }
    }

    public static String decryptNew(String content) {
        if (TextUtils.isEmpty(content)) {
            return "AES decrypt: the content is null!";
        }
        //判断秘钥是否为16位
        if (!TextUtils.isEmpty(KEY) && KEY.length() == 16) {
            try {
                //对密码进行编码
                byte[] bytes = KEY.getBytes(ENCODING);
                //设置解密算法，生成秘钥
                SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM);
                // "算法/模式/补码方式"
                Cipher cipher = Cipher.getInstance(CIPHER_PADDING);
                //选择解密
                cipher.init(Cipher.DECRYPT_MODE, skeySpec);
                //先进行Base64解码
//                byte[] decodeBase64 = Base64Utils.decodeFromString(content);
                byte[] decodeBase64 = Base64.decodeBase64(content);
                //根据待解密内容进行解密
                byte[] decrypted = cipher.doFinal(decodeBase64);
                //将字节数组转成字符串
                return new String(decrypted, ENCODING);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            return "AES decrypt: the aesKey is null or error!";
        }
    }

    public static final Charset DEFAULT_CHARSET;

    static {
        DEFAULT_CHARSET = Charsets.UTF_8;
    }

    @Nullable
    public static String decryptFormBase64ToString(@Nullable String content, String aesTextKey) {
        byte[] hexBytes = decryptFormBase64(content, aesTextKey);
        return hexBytes == null ? null : new String(hexBytes, DEFAULT_CHARSET);
    }

    @Nullable
    public static byte[] decryptFormBase64(@Nullable String content, String aesTextKey) {
        return decryptFormBase64(content.getBytes(DEFAULT_CHARSET), aesTextKey);
    }

    public static byte[] decryptFormBase64(byte[] content, String aesTextKey) {
        return decrypt(Base64.decodeBase64(content), aesTextKey);
    }

    public static byte[] decrypt(byte[] content, String aesTextKey) {
        return decrypt(content, ((String) Objects.requireNonNull(aesTextKey)).getBytes(DEFAULT_CHARSET));
    }

    public static byte[] decrypt(byte[] encrypted, byte[] aesKey) {
        return Pkcs7Encoder.decode(aes(encrypted, aesKey, 2));
    }

    private static byte[] aes(byte[] encrypted, byte[] aesKey, int mode) {

        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
            cipher.init(mode, keySpec, iv);
            return cipher.doFinal(encrypted);
        } catch (Exception var6) {
            var6.printStackTrace();
        }
        return null;
    }

    private static class Pkcs7Encoder {
        private static final int BLOCK_SIZE = 32;

        private Pkcs7Encoder() {
        }

        private static byte[] encode(byte[] src) {
            int count = src.length;
            int amountToPad = 32 - count % 32;
            byte pad = (byte) (amountToPad & 255);
            byte[] pads = new byte[amountToPad];

            int length;
            for (length = 0; length < amountToPad; ++length) {
                pads[length] = pad;
            }

            length = count + amountToPad;
            byte[] dest = new byte[length];
            System.arraycopy(src, 0, dest, 0, count);
            System.arraycopy(pads, 0, dest, count, amountToPad);
            return dest;
        }

        private static byte[] decode(byte[] decrypted) {
            int pad = decrypted[decrypted.length - 1];
            if (pad < 1 || pad > 32) {
                pad = 0;
            }

            return pad > 0 ? Arrays.copyOfRange(decrypted, 0, decrypted.length - pad) : decrypted;
        }
    }

    /**
     * 解密
     *
     * @param encryptStr 解密的字符串
     * @param decryptKey 解密的key值
     * @return
     * @throws Exception
     */
    public static String decrypt(String encryptStr, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(decryptKey.getBytes(), 0, 16));
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"), iv);

        // 采用base64算法进行转码,避免出现中文乱码
        byte[] encryptBytes = Base64.decodeBase64(encryptStr);
        byte[] decryptBytes = cipher.doFinal(encryptBytes);
        return new String(decryptBytes);
    }

    public static String encrypt(String content) throws Exception {
        return encrypt(content, KEY);
    }

    public static String decrypt(String encryptStr) throws Exception {
        return decrypt(encryptStr, KEY);
    }


    public static void main(String[] args) throws Exception {
        Map map = new HashMap<String, String>();
        map.put("temperatureType", "value");
        map.put("removeType", "汉字");
        String content = JSONObject.toJSONString(map);
        System.out.println("加密前：" + content);

        String encrypt = encrypt(content, KEY);
        System.out.println("加密后：" + encrypt);

        String decrypt = decrypt("D184C9A554E7B38182F30046B81FF6C52D4EC3345558040793E1F001E2C26CFED6F78F17C444EDC5C17109D86255C99C73D9CAC4EF9938A06F758136E7293CB1B25DDCBDB9E4BCC8C7BF9F6BCF6969B7", KEY);
        System.out.println("解密后：" + decrypt);
    }

}
