package com.logosdata.security.util;

import com.alibaba.fastjson.JSONObject;
import com.logosdata.security.SM2;
import com.logosdata.security.SM3;
import com.logosdata.security.SM4;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.math.ec.ECPoint;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.math.BigInteger;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * {@code SignUtils} 签名工具类
 *
 * @author Hengchen.Sun
 * @version 1.0.0
 * @date 2021-02-18
 * @since ver.1.0.0
 */
@Slf4j
public final class SignUtils {

	private SignUtils(){}

	/**
	 * 通用解密方法
	 * @param json
	 * @param secretKey
	 * @return
	 * @throws Exception
	 */
	public static String decryptData(String json, String secretKey) throws Exception {
		JSONObject jsonObject = JSONObject.parseObject(json);
		String decData = null;

		SM4 sm4 = new SM4();
		sm4.setSecretKey(secretKey);
		sm4.setHexString(false);
		// 响应业务报文data
		String dataString =jsonObject.getString("data");
		decData = sm4.decryptDataToString_ECB(dataString, "UTF-8");
		// 响应签名sign
		String signString = jsonObject.getString("sign");
		byte[] sign = Base64.getDecoder().decode(signString.getBytes());
		Object signature1 =toObject(sign);
		log.info("签名：" + signature1.toString());
		String[] arr = signature1.toString().split(",");
		BigInteger r = new BigInteger(arr[0], 16);
		BigInteger s = new BigInteger(arr[1], 16);
		SM2.Signature signature = new SM2.Signature(r, s);
		System.err.println(signature);

		// sm2加密
		SM2 sm2 = new SM2();
		// 读取公钥
		ECPoint publicKey = sm2.importPublicKey(getConfigPublicKey().get("publicKey").toString());
		String IDA = "taxhelper";
		log.info("签名信息：" + decData);
		byte[] hash = SM3.hash(decData.getBytes("UTF-8"));
		// 验签
		boolean flag = sm2.verify(new String(hash), signature, IDA, publicKey);
		System.out.println(flag);
		if (flag) {
			log.info("验证签名成功");
			return decData;
		} else {
			log.info("验证签名失败");

			// String errorMsg = "{\"message\":\"验证签名失败\"}";
			String errorMsg = "验证签名失败";

			throw new RuntimeException(errorMsg);
		}
	}

	/**
	 * 通用加密方法
	 * @param param
	 * @param secretKey
	 * @return
	 * @throws Exception
	 */
	public static Map<String, Object> encryptData(Map<String, Object> param, String secretKey) throws Exception {
		Map<String, Object> newParam = new HashMap<>();
		JSONObject jsonObject = new JSONObject();
		jsonObject.putAll(param);
		String decData = jsonObject.toString();

		SM4 sm4 = new SM4();
		// 加密密钥，由双方协定产生
		sm4.setSecretKey(secretKey);
		sm4.setHexString(false);

		log.info("ECB模式加密");
		String encData = sm4.encryptDataToString_ECB(decData, "UTF-8");
		log.info("密文: " + encData);

		byte[] hash = SM3.hash(decData.getBytes("UTF-8"));

		SM2 sm2 = new SM2();
		ECPoint publicKey = sm2.importPublicKey(getConfigPublicKey().get("publicKey").toString());
		byte[] sign = sm2.encrypt(hash, publicKey);

		newParam = new HashMap<>();
		newParam.put("data", encData);
		newParam.put("sign", Base64.getEncoder().encodeToString(sign));
		log.info("data：" + encData);
		log.info("sign：" + Base64.getEncoder().encodeToString(sign));
		return newParam;
	}

	public static Object toObject(byte[] bytes) throws Exception {
		Object obj = null;
		try {
			// bytearray to object
			ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
			ObjectInputStream oi = new ObjectInputStream(bi);

			obj = oi.readObject();
			log.error("签名对象：", obj);
			bi.close();
			oi.close();
		} catch (Exception e) {
			System.out.println("translation" + e.getMessage());
			e.printStackTrace();
		}
		return obj;
	}

	public static Map<String, Object> getConfigPublicKey() {
		Map<String, Object> map = new HashMap<String, Object>();
		Properties props = System.getProperties(); // 获得系统属性集
		String osName = props.getProperty("os.name").toLowerCase(); // 操作系统名称
		if (osName.indexOf("linux") != -1 || osName.indexOf("unix") != -1) {
//			map.put("publicKey", "/home/logos/dzdk-api-gateway/publickey.pem");
//			map.put("privateKey", "/home/logos/dzdk-api-gateway/privatekey.pem");
//			map.put("publicKey", "/opt/wmproject/SBY-Secret/publickey.pem");
//			map.put("privateKey", "/opt/wmproject/SBY-Secret/privatekey.pem");
			map.put("publicKey", "/excel/publickey.pem");
			map.put("privateKey", "/excel/privatekey.pem");
		}
		if (osName.indexOf("mac") != -1){
			map.put("publicKey", "/Users/jimmy/Developer/repos/cert/taxhelpor/publickey.pem");
			map.put("privateKey", "/Users/xuqiqi/IdeaProjects/logos/dzdk-api-gateway/privatekey.pem");
		}
		if (osName.indexOf("windows") != -1) {
			// 开发测试
			map.put("publicKey", "D:/publickey.pem");
			map.put("privateKey", "D:/常用文本文件/代征代扣/封装接口资料/开发测试环境密钥/privatekey.pem");
//            // 生产
//            map.put("publicKey", "D:/常用文本文件/代征代扣/封装接口资料/生产环境密钥/publickey.pem");
//            map.put("privateKey", "D:/常用文本文件/代征代扣/封装接口资料/生产环境密钥/privatekey.pem");
		}
		return map;
	}


}
