package com.hfkj.common.utils;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Map;
import java.util.TreeMap;

public class PetroEncryptUtil {


    /**
     * 生成签名
     *
     * @param signMaps
     * @return
     * @throws Exception
     */
    public static String generateSign(Map<String, Object> signMaps) {
        StringBuilder sb = new StringBuilder();
        TreeMap<String, Object> sortedMap = new TreeMap<>(signMaps);
        // 字典序
        for (Map.Entry<String, Object> entry : sortedMap.entrySet()) {
            String key = entry.getKey();
            String value = (String) entry.getValue();

            // 为空不参与签名、参数名区分大小写
            if (!"sign".equals(key)) {
                sb.append(key).append("=").append(value).append("&");
            }

        }
        sb = new StringBuilder(sb.substring(0, sb.length() - 1));
        // MD5加密
        return md532(sb.toString());
    }

    /***
     * MD5加码 生成32位md5码
     */
    public static String md532(String inStr) {
        MessageDigest md5;
        try {
            md5 = MessageDigest.getInstance("MD5");

        } catch (Exception e) {
            System.out.println(e);
            e.printStackTrace();
            return "";
        }
        char[] charArray = inStr.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuilder hexValue = new StringBuilder();
        for (byte md5Byte : md5Bytes) {
            int val = ((int) md5Byte) & 0xff;
            if (val < 16)
                hexValue.append("0");
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }


    /**
     * 加密解密算法
     *
     * @param inStr     加密字符串
     * @param secretKey 秘钥
     *                  算法：
     *                  1：加密字符串和秘钥转换成字符数组；
     *                  2：秘钥去重复
     *                  3：循环一（秘钥字符串数组）{ 循环二（加密字符串数组）{
     *                  秘钥字符的ASC码 与 加密字符的ASC码 进行二进制异或运算
     *                  }
     *                  }
     *                  4：把字符串转为16进制
     */
    private static String convert(String inStr, String secretKey) {
        char[] a = inStr.toCharArray();
        char[] s = rmRepeated(secretKey).toCharArray();
        for (int i = 0; i < s.length; i++) {
            for (int j = 0; j < a.length; j++) {
                a[j] = (char) (a[j] ^ s[i]);
            }
        }
        return new String(a);
    }

    /**
     * 清除字符串中重复字母算法
     *
     * @param s
     * @return
     */
    private static String rmRepeated(String s) {
        int len = s.length();
        int k = 0;
        int count = 0;
        String str = "";
        char[] c = new char[len];
        for (int i = 0; i < len; i++) {
            c[i] = s.charAt(i);
        }
        for (int i = 0; i < len; i++) {
            k = i + 1;
            while (k < len - count) {
                if (c[i] == c[k]) {
                    for (int j = k; j < len - 1; j++) {
                        c[j] = c[j + 1];// 出现重复字母，从k位置开始将数组往前挪位
                    }
                    count++;// 重复字母出现的次数
                    k--;
                }
                k++;
            }
        }
        for (int i = 0; i < len - count; i++) {
            str += String.valueOf(c[i]);
        }
        return str;
    }

    /*
     * 将字符串编码成16进制数字,适用于所有字符（包括中文）
     */
    private static String hexString = "0123456789ABCDEF";

    public static String encode(String str) {
        // 根据默认编码获取字节数组
        String r;
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        // 将字节数组中每个字节拆解成2位16进制整数
        for (byte aByte : bytes) {
            sb.append(hexString.charAt((aByte & 0xf0) >> 4));
            sb.append(hexString.charAt((aByte & 0x0f)));
        }
        r = sb.toString();
        return r;
    }

    /*
     * 将16进制数字解码成字符串,适用于所有字符（包括中文）
     */
    public static String decode(String bytes) {
        String r = "";
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(bytes.length() / 2);
            // 将每2位16进制整数组装成一个字节
            for (int i = 0; i < bytes.length(); i += 2) {
                byteArrayOutputStream.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString.indexOf(bytes.charAt(i + 1))));
            }
            r = byteArrayOutputStream.toString("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return r;
    }

    /**
     * 加密
     *
     * @param inStr     原字符串
     * @param secretKey 秘钥
     * @return
     */
    public static String encrypt(String inStr, String secretKey) {
        String hexStr = convert(inStr, secretKey);
        return encode(hexStr);
    }

    /**
     * 解密
     *
     * @param inStr     原字符串
     * @param secretKey 秘钥
     * @return
     */
    public static String decrypt(String inStr, String secretKey) {
        String hexStr = decode(inStr);
        return convert(hexStr, secretKey);
    }

}
