package com.gree.mall.manager.utils.sm4;

import com.alibaba.fastjson.JSON;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class SMHttpTool {

    private static Base64.Encoder encoder = Base64.getEncoder();
    private static Base64.Decoder decoder = Base64.getDecoder();
    // 采用国密算法
    private static final String ALG_SM = "SM";

    /**
     *
     * @param jObject 请求头及参数
     * @param bankUrl  请求地址
     * @param bankPubkey 公钥
     * @param bankPrivkey 私钥
     * @param sm4key  对称加密秘钥
     * @param uid  分配账号
     * @return 请求返回结果
     * @throws Exception
     */
    public static Map<String,Object> doProcess(JsonObject jObject,String apiCode,String bankUrl,String bankPubkey,String bankPrivkey,String sm4key,String uid) throws Exception {
        // 引入BC库
        Security.addProvider(new BouncyCastleProvider());
        JsonObject object = new JsonObject();
        // 签名
        object.addProperty("sigdat", "__signature_sigdat__");
        object.addProperty("sigtim", DCHelper.getTime());
        jObject.add("signature", object);
        String source = DCHelper.serialJsonOrdered(jObject);
        log.info("请求银行签名原文: " + source);
        byte[] signature1 = DCCryptor.CMBSM2SignWithSM3(getID_IV(uid), decoder.decode(bankPrivkey), source.getBytes(StandardCharsets.UTF_8));
        String sigdat1 = new String(encoder.encode(signature1));
      //  System.out.println("签名结果: " + sigdat1);
        object.addProperty("sigdat", sigdat1);

        // SM4-CBC加密
        String plaintxt = jObject.toString();
       // System.out.println("加密前req:  " + plaintxt);
        byte[] enInput = DCCryptor.CMBSM4EncryptWithCBC(sm4key.getBytes(), getID_IV(uid), plaintxt.getBytes(StandardCharsets.UTF_8));

        String req = new String(encoder.encode(enInput));
      //  System.out.println("加密后req:  " + req);

        // 发送请求
        HashMap<String, String> map = new HashMap<>();
        map.put("UID", uid);
        map.put("ALG", ALG_SM);
        map.put("DATA", URLEncoder.encode(req, "utf-8"));
        map.put("FUNCODE", apiCode);
        String res = DCHelper.doPostForm(bankUrl, map);
       // System.out.println("res:  " + res);
        try {
            decoder.decode(res);
        } catch (Exception e) {
            log.error("访问返回错误.返回结果{}" ,res);
            return null;
        }

        // 解密请求
        String resplain = new String(DCCryptor.CMBSM4DecryptWithCBC(sm4key.getBytes(), getID_IV(uid), decoder.decode(res)), StandardCharsets.UTF_8);
        log.info("请求银行返回解密结果： " + resplain);

        // 验签
        JsonObject object2 = new GsonBuilder().create().fromJson(resplain, JsonObject.class);
        JsonObject object3 = object2.getAsJsonObject("signature");
        String resSign = object3.get("sigdat").getAsString();
        object3.addProperty("sigdat", "__signature_sigdat__");
        object2.add("signature", object3);
        String resSignSource = DCHelper.serialJsonOrdered(object2);
        boolean verify = DCCryptor.CMBSM2VerifyWithSM3(getID_IV(uid), decoder.decode(bankPubkey), resSignSource.getBytes(StandardCharsets.UTF_8), decoder.decode(resSign));
        if(verify){
            return (Map) JSON.parseObject(resSignSource).get("response");
        } else {
            log.info("返回结果验签失败");
            return null;
        }
    }

    private static byte[] getID_IV(String uid) {
        String userid = uid + "0000000000000000";
        return userid.substring(0, 16).getBytes();
    }


}
