package com.tzy.framework.pay.util;

import com.tzy.common.utils.StringUtils;
import com.tzy.framework.pay.dto.QmZgOrderInfoDto;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Enumeration;
import java.util.List;

import static org.apache.commons.codec.binary.Base64.decodeBase64;

/**
 * Util汇总整合工具类,主要对请求和回复的报文进行组装解析，签名，验签，加密，解密等操作
 *
 * @author Roi
 */
public class Util {
    private static final Logger logger = LoggerFactory.getLogger(Util.class);
    /**
     * 签名验签算法，值为{@value}
     */
    public final static String ALGORITHM_SHA256WITHRSA = "SHA256withRSA";
    /**
     * 证书类型，值为{@value}
     */
    public static final String CERT_TYPE_JKS = "JKS";
    /**
     * 证书类型，值为{@value}
     */
    public static final String CERT_TYPE_PKCS12 = "PKCS12";
    /**
     * 证书类型，值为{@value}
     */
    public static final String CERT_TYPE_PKCS8 = "PKCS8";
    protected static MessageDigest messagedigest = null;
    private static KeyStore keyStore = null;//签名证书

    /**
     * encrypt
     *
     * @param plainText password
     * @return boolean
     * @throws Exception
     */
    public static String encrypt(String plainText, String password) throws Exception {

        SecureRandom random = new SecureRandom();
        DESKeySpec desKey = new DESKeySpec(password.getBytes());
        //创建一个密匙工厂，然后用它把DESKeySpec转换成
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey securekey = keyFactory.generateSecret(desKey);
        //Cipher对象实际完成加密操作
        Cipher cipher = Cipher.getInstance("DES");
        //用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量
        cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
        //现在，获取数据并加密
        //正式执行加密操作
        byte[] encryptResult = cipher.doFinal(plainText.getBytes()); //按单部分操作加密或解密数据，或者结束一个多部分操作
        return byteArr2HexString(encryptResult);
    }

    /**
     * 字节数组转换为十六进制字符串
     *
     * @param byteArr 字节数组
     * @return 十六进制字符串
     */
    public static String byteArr2HexString(byte[] byteArr) {
        if (byteArr == null) {
            return "null";
        }
        StringBuffer sb = new StringBuffer();

        for (int k = 0; k < byteArr.length; k++) {
            if ((byteArr[k] & 0xFF) < 16) {
                sb.append("0");
            }
            sb.append(Integer.toString(byteArr[k] & 0xFF, 16));
        }
        return sb.toString();
    }

    /**
     * 从私钥证书中获取PKCS12标准私钥<br/>
     *
     * @param keyFileIn 私钥文件流 .pfx
     * @param keypwd    证书密码
     * @return：私钥
     */
    public static PrivateKey getPriKeyPkcs12(InputStream keyFileIn, String keypwd) {
        return getPriKey(keyFileIn, keypwd, CERT_TYPE_PKCS12);
    }

    /**
     * 从私钥证书中获取私钥
     *
     * @param keyFileIn 证书文件流.pfx, .keystore)
     * @param keypwd    证书密码
     * @param type      证书类型
     * @return：私钥
     */
    public static PrivateKey getPriKey(InputStream keyFileIn, String keypwd, String type) {
        PrivateKey privateKey = null;
        getKeyStore(keyFileIn, keypwd, type);
        try {
            Enumeration<String> aliasenum = keyStore.aliases();
            String keyAlias = null;
            if (aliasenum.hasMoreElements()) {
                // 第一个条目
                keyAlias = (String) aliasenum.nextElement();
            }
            privateKey = (PrivateKey) keyStore.getKey(keyAlias, keypwd.toCharArray());
        } catch (Exception e) {
            logger.error("Fail: get private key from private certificate", e);
        }
        return privateKey;
    }

    /**
     * 将证书文件读取为证书存储对象：证书文件类型可为：JKS（.keystore等），PKCS12（.pfx）
     *
     * @param keyFileIn 证书文件文件流
     * @param keypwd    证书密码
     * @param type      证书类型
     * @return 证书对象
     */
    public static KeyStore getKeyStore(InputStream keyFileIn, String keypwd, String type) {
        try {
            if (CERT_TYPE_JKS.equals(type)) {
                keyStore = KeyStore.getInstance(type);
            } else if (CERT_TYPE_PKCS12.equals(type)) {
                /**
                 * 动态注册SUN JCE<br/>
                 * JCE（Java Cryptography Extension）是一组包，它们提供用于加密、密钥生成和协商以及 Message
                 * Authentication Code（MAC）算法的框架和实现。<br/>
                 * 设置安全提供者为BouncyCastleProvider
                 */
                if (Security.getProvider("BC") == null) {
                    // 将提供程序添加到下一个可用位置。
                    Security.addProvider(new BouncyCastleProvider());
                } else {
                    Security.removeProvider("BC");
                    Security.addProvider(new BouncyCastleProvider());
                }
                keyStore = KeyStore.getInstance(type);
            }
            char[] nPassword = null;
            nPassword = null == keypwd || "".equals(keypwd.trim()) ? null : keypwd.toCharArray();
            keyStore.load(keyFileIn, nPassword);
            if (keyFileIn != null)
                keyFileIn.close();
            return keyStore;
        } catch (Exception e) {
            if (Security.getProvider("BC") == null) {
                logger.info("BC Provider not installed.");
            }
            logger.error("Fail: load privateKey certificate", e);
        } finally {
            if (keyFileIn != null)
                try {
                    keyFileIn.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        return null;
    }

    /**
     * 从私钥证书中获取JKS标准私钥<br/>
     *
     * @param keyFileIn 私钥文件流 .keystore .jks
     * @param keypwd    密码
     * @return
     */

    public static PrivateKey getPriKeyJks(InputStream keyFileIn, String keypwd, String type) {
        return getPriKey(keyFileIn, keypwd, CERT_TYPE_JKS);
    }

    /**
     * 从私钥证书中获取PKCS8标准私钥<br/>
     *
     * @param keyFileIn 私钥文件流
     * @return 私钥
     */
    public static PrivateKey getPriKeyPkcs8(InputStream keyFileIn) {
        PrivateKey privateKey = null;
        try {
            byte[] buffer = readFile(keyFileIn);
            buffer = decodeBase64(buffer);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            privateKey = keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            logger.error("Fail: get private key from private certificate", e);
        } finally {
            if (keyFileIn != null)
                try {
                    keyFileIn.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        return privateKey;
    }

    /**
     * 从公钥证书中获取公钥<br/>
     *
     * @param keyFileIn 文件流 .cer
     * @return
     */
    public static PublicKey getPubKey(InputStream keyFileIn) {
        java.security.cert.X509Certificate publicCert = getPubCert(keyFileIn, null);
        PublicKey publicKey = publicCert.getPublicKey();
        return publicKey;
    }

    /**
     * 读取文件的方法<br/>
     *
     * @param keyFileIn 文件流
     * @return
     * @throws Exception
     */
    private static byte[] readFile(InputStream keyFileIn) throws Exception {
        BufferedReader br;
        InputStreamReader isr = new InputStreamReader(keyFileIn);
        br = new BufferedReader(isr);
        String readLine;
        StringBuilder sb = new StringBuilder();
        while ((readLine = br.readLine()) != null) {
            if (readLine.startsWith("--")) {
                continue;
            }
            sb.append(readLine);
        }
        br.close();
        isr.close();
        keyFileIn.close();
        return sb.toString().getBytes();
    }

    /**
     * 读取公钥证书<br/>
     *
     * @param keyFileIn 文件路径 .cer
     * @return 证书对象
     */
    public static java.security.cert.X509Certificate getPubCert(InputStream keyFileIn, String provider) {
        CertificateFactory cf = null;
        InputStream in = null;
        java.security.cert.X509Certificate x509Certificate = null;
        try {
            if ("BC".equals(provider)) {
                cf = CertificateFactory.getInstance("X.509", "BC");
            } else {
                cf = CertificateFactory.getInstance("X.509");
            }
            in = keyFileIn;
            x509Certificate = (java.security.cert.X509Certificate) cf.generateCertificate(in);
            if (in != null)
                in.close();
        } catch (Exception e) {
            logger.error("Fail: load public certificate", e);
            return null;
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error("Fail: close FileInputStream", e);
                }
            }
        }
        return x509Certificate;
    }

    public static byte[] sign(byte[] rawData, PrivateKey privateKey, String algorithm) {
        try {
            Signature e = Signature.getInstance(algorithm);
            e.initSign(privateKey);
            e.update(rawData);
            return e.sign();
        } catch (Exception e) {
            System.out.println("签名失败");
            e.printStackTrace();
            return null;
        }
    }

    public static Boolean verify(byte[] rawData, byte[] signature, PublicKey publicKey, String algorithm) {
        try {
            Signature e = Signature.getInstance(algorithm);
            e.initVerify(publicKey);
            e.update(rawData);
            return Boolean.valueOf(e.verify(signature));
        } catch (Exception e) {
            System.out.println("验签失败");
            e.printStackTrace();
            return null;
        }
    }
    public static byte[] hexString2ByteArr(String hexstring) {
        if(hexstring != null && hexstring.length() % 2 == 0) {
            byte[] dest = new byte[hexstring.length() / 2];

            for(int i = 0; i < dest.length; ++i) {
                String val = hexstring.substring(2 * i, 2 * i + 2);
                dest[i] = (byte)Integer.parseInt(val, 16);
            }

            return dest;
        } else {
            return new byte[0];
        }
    }

    /**
     * 组装数据
     */
    public static String addData2File(List<QmZgOrderInfoDto> data,String type,String merchantNo){
        if(null == data || StringUtils.isEmpty(type) || StringUtils.isEmpty(merchantNo)) return null;
        String filePath = "";
        int size = data.size();
        switch (type){
            case "02": //按金额划付



                break;
            case "04":
                break;
            default:
                break;
        }
        return filePath;
    }


}
