package com.tiesheng.encrypt.config;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.ECKeyUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.LogFactory;
import com.tiesheng.annotation.encrypt.EncryptedRespBody;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;


/**
 * @author hao
 */
@ControllerAdvice
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    @Autowired
    EncryptConfig encryptConfig;

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends
            HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        if (!encryptConfig.isEnable()) {
            return body;
        }

        boolean encrypt = AnnotationUtil.getAnnotation(returnType.getContainingClass(), EncryptedRespBody.class) != null;
        if (!encrypt) {
            return body;
        }

        try {

            String content = JSONUtil.toJsonStr(body);
            String respData = JSONUtil.parseObj(content).getStr("data");

            if (StrUtil.isEmpty(respData)) {
                // 无需加密
                return body;
            }

            JSONObject resp = JSONUtil.parseObj(content);
            resp.set("encrypted", true);
            if (resp.getInt("code") == 200) {
                // 用公钥进行加密
                ECPrivateKeyParameters privateKeyParameters = ECKeyUtil.toSm2PrivateParams(encryptConfig.getPrivateQ());
                ECPublicKeyParameters publicKeyParameters = ECKeyUtil.getPublicParams(privateKeyParameters);
                SM2 sm2 = SmUtil.sm2(privateKeyParameters, publicKeyParameters);
                String decrypt = sm2.encryptHex(respData, KeyType.PublicKey);
                resp.set("data", decrypt.substring(2));
            }
            return resp;
        } catch (Exception var17) {
            LogFactory.get().info("加密数据异常", var17);
        }

        return body;
    }

}
