package com.lightinit.hsdataportal.common;

import org.apache.commons.io.IOUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;

public class RSAUtils {
	//private static String RSAPrivateKeyStore = "RSAPrivateKeyStore_devops-server.txt";
	//private static String PROPERTY = System.getProperty("user.dir");
	private static String RSAPrivateKeyStore = RSAUtils.class.getClassLoader().getResource("rsa-password/RSAPrivateKeyStore_devops-server.txt").getFile();
	private static String PROPERTY = null;
	private static int KEY_SIZE = 1024;

	private static Provider provider = new BouncyCastleProvider();

	private static PrivateKey privateKey;
	private static PublicKey publicKey;

	private static ThreadLocal<Cipher> localCipher = new ThreadLocal<Cipher>() {
		protected synchronized Cipher initialValue() {
			Cipher cipher = null;
			try {
				cipher = Cipher.getInstance("RSA");
			} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
				e.printStackTrace(System.err);
			}
			return cipher;
		}
	};

	public static KeyPair generateKeyPair() throws Exception {
		try {
			KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", provider);
			keyPairGen.initialize(KEY_SIZE, new SecureRandom());
			KeyPair keyPair = keyPairGen.generateKeyPair();
			privateKey = keyPair.getPrivate();
			publicKey = keyPair.getPublic();
			return keyPair;
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}
	}

	public static void saveKeyPair(KeyPair kp) throws Exception {
		BufferedWriter oos = null;
		try {
			PrivateKey aPrivate = kp.getPrivate();
			String privateKeyString = new String(Base64.encode(aPrivate.getEncoded()));
			oos = new BufferedWriter(new FileWriter(new File(PROPERTY, RSAPrivateKeyStore)));
			System.out.println(oos.toString());
			oos.write(privateKeyString);
		} finally {
			IOUtils.closeQuietly(oos);
		}
	}

	public static void loadKeyPair() throws Exception {
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(new File(PROPERTY,RSAPrivateKeyStore)));
			StringBuilder sb = new StringBuilder();
			String readLine = null;
			while (null != (readLine = br.readLine())) {
				sb.append(readLine);
			}
			String privateKeyStr = sb.toString();
			privateKey = initialPrivateKey(privateKeyStr);
			publicKey = generatePublicKeyByPrivateKey(privateKey);
		} catch (IOException e) {
			throw new Exception("私钥数据读取错误");
		} catch (NullPointerException e) {
			throw new Exception("私钥输入流为空");
		} finally {
			IOUtils.closeQuietly(br);
		}
	}

	public static String encrypt(String plainText) {
		String cipherText = null;
		try {
			byte[] data = plainText.getBytes();
			Cipher cipher = localCipher.get();
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] bytes = cipher.doFinal(data);
			cipherText = new String(Base64.encode(bytes));
		} catch (Exception ex) {
			ex.printStackTrace(System.err);
		}

		return cipherText;
	}

	public static String decrypt(String cipherText) {
		String plainText = null;
		try {
			byte[] data = Base64.decode(cipherText);
			Cipher cipher = localCipher.get();
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] bytes = cipher.doFinal(data);
			plainText = new String(bytes);
		} catch (Exception ex) {
			ex.printStackTrace(System.err);
		}

		return plainText;
	}

	private static PrivateKey initialPrivateKey(String privateKeyStr) throws Exception {
		try {
			byte[] buffer = Base64.decode(privateKeyStr);
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			return keyFactory.generatePrivate(keySpec);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("私钥非法");
		} catch (NullPointerException e) {
			throw new Exception("私钥数据为空");
		}
	}

	private static PublicKey generatePublicKeyByPrivateKey(PrivateKey privateKey) {
		PublicKey publicKey = null;
		try {
			KeyFactory kf = KeyFactory.getInstance("RSA");
			RSAPrivateKeySpec priv = kf.getKeySpec(privateKey, RSAPrivateKeySpec.class);
			RSAPublicKeySpec keySpec = new RSAPublicKeySpec(priv.getModulus(), BigInteger.valueOf(65537));
			publicKey = kf.generatePublic(keySpec);
			System.out.println(">>>> PublicKey: " + new String(Base64.encode(publicKey.getEncoded())) + " <<<<");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
		return publicKey;
	}

	public static void initialPublicKey(String publicKeyStr) throws Exception {
		try {
			byte[] buffer = Base64.decode(publicKeyStr);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
			publicKey = keyFactory.generatePublic(keySpec);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("公钥非法");
		} catch (NullPointerException e) {
			throw new Exception("公钥数据为空");
		}
	}


	/*public static void main(String[] args) {
        String RSAPrivateKeyStore = RSAUtils.class.getClassLoader().getResource("rsa-password/RSAPrivateKeyStore_devops-server.txt").getFile();
        File file = new File(RSAPrivateKeyStore);
        System.out.println(file.length());
        System.out.println(RSAPrivateKeyStore);
    }*/
}
