package com.hzs.third.pay.util;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.hzs.third.pay.constants.JdPayConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

/**
 * 京东加密工具类
 */
@Slf4j
public class JdPayUtil {

    /**
     * 请求订单
     *
     * @param path      访问路径
     * @param body      请求体
     * @param secretKey 私钥
     * @param accessKey 公钥
     * @return
     */
    public static String requestOrder(String path, String body, String secretKey, String accessKey) {
        // 时间戳（秒）
        long timestamp = System.currentTimeMillis() / 1000;

        // SHA1 加密串
        String sha1Str = "secretKey=" + secretKey +
                "&timestamp=" + timestamp +
                "&path=" + path +
                "&body=" + body;
        String token = SecureUtil.sha1(sha1Str).toUpperCase();

        // 请求京东获取扫码地址
        return HttpUtil.createPost(JdPayConstants.PAY_URL + path)
                .body(body)
                .header("Content-type", "application/json")
                .header("accessKey", accessKey)
                .header("timestamp", Long.toString(timestamp))
                .header("token", token)
                .execute()
                .body();
    }

    /**
     * @param encryptSrc 需要加密的字符串
     * @param encryptKey 加密的aes key
     * @return
     * @throws Exception
     */
    public static String encrypt(String encryptSrc, String encryptKey) throws Exception {
        // 判断encryptKey是否为空
        if (StringUtils.isBlank(encryptKey)) {
            log.error("encryptKey 加密key为null");
            return null;
        }
        // 判断encryptKey是否为16位
        if (encryptKey.length() != 16) {
            log.error("encryptKey长度小于16位");
            return null;
        }
        byte[] raw = encryptKey.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        // "算法/模式/补码方式"
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(encryptSrc.getBytes(StandardCharsets.UTF_8));

        // 此处使用BASE64做转码功能，同时能起到2次加密的作用。
        return new Base64().encodeToString(encrypted);
    }

    // 解密
    public static String decrypt(String encryptSrc, String encryptKey) throws Exception {
        try {
            // 判断encryptKey是否为null
            if (StringUtils.isBlank(encryptKey)) {
                log.error("encryptKey 加密key为null");
                return null;
            }
            // 判断encryptKey是否为16位
            if (encryptKey.length() != 16) {
                log.error("encryptKey长度小于16位");
                return null;
            }
            byte[] raw = encryptKey.getBytes(StandardCharsets.UTF_8);
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            // 先用base64解密
            byte[] encrypted1 = new Base64().decode(encryptSrc);
            try {
                byte[] original = cipher.doFinal(encrypted1);
                return new String(original, StandardCharsets.UTF_8);
            } catch (Exception e) {
                log.info("加密异常", e);
                return null;
            }
        } catch (Exception e) {
            log.info("加密异常:", e);
            return null;
        }
    }


    /**
     * 通过access_token的40位数字获取16位的aes key
     *
     * @param pwd 需要加密的字符串
     * @return
     */
    public static String getAesKey(String pwd) {
        String md5 = "";
        try {
            // 创建加密对象
            MessageDigest md = MessageDigest.getInstance("md5");
            // 计算MD5函数
            md.update(pwd.getBytes());
            byte[] bytes = md.digest();
            int i;
            StringBuilder sb = new StringBuilder("");
            for (byte aByte : bytes) {
                i = aByte;
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    sb.append("0");
                }
                sb.append(Integer.toHexString(i));
            }
            md5 = sb.toString();
            // 截取32位md5为16位
            md5 = md5.substring(8, 24);
            return md5;
        } catch (Exception e) {
            log.error("md5加密异常：", e);
            e.printStackTrace();
        }

        return md5;
    }
}
