package cn.hanghui.outapi.platform.common.aspect;

import cn.hanghui.outapi.platform.common.annotation.DecryptParam;
import cn.hanghui.outapi.platform.common.entity.dto.SecretDto;
import cn.hanghui.outapi.platform.common.exception.CommonException;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;

@Aspect
@Component
public class DecryptAspect {

    @Value("${private-key}")
    private String privateKey;

    /**
     * 配置织入点
     */
    @Pointcut("@annotation(cn.hanghui.outapi.platform.common.annotation.DecryptBySm2)")
    public void decryptPointCut() {
    }

    /**
     * 参数解密
     *
     * @param joinPoint joinPoint
     */
    @Before(value = "decryptPointCut()")
    public void before(JoinPoint joinPoint) {
        try {
            HttpServletRequest request =
                    ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes()))
                            .getRequest();
            String body = ServletUtil.getBody(request);
            SecretDto secretDto = JSON.parseObject(body, SecretDto.class);
            SM2 sm2 = SmUtil.sm2(privateKey, null);
            byte[] decrypt = sm2.decrypt(secretDto.getData(), KeyType.PrivateKey);
            String decryptStr = new String(decrypt);
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method targetMethod = signature.getMethod();
            Annotation[][] parameterAnnotations = targetMethod.getParameterAnnotations();
            int index = -1;
            A:
            for (int i = 0; i < parameterAnnotations.length; i++) {
                for (Annotation annotation : parameterAnnotations[i]) {
                    if (Objects.equals(annotation.annotationType(), DecryptParam.class)) {
                        index = i;
                        break A;
                    }
                }
            }
            Object[] args = joinPoint.getArgs();
            if (index != -1) {
                Object param = args[index];
                Class<?> paramClass = param.getClass();
                Object data = JSON.parseObject(decryptStr, paramClass);
                Field[] fields = paramClass.getDeclaredFields();
                for (Field field : fields) {
                    String fieldName = field.getName();
                    Method get = paramClass.getDeclaredMethod("get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));
                    Method set = paramClass.getDeclaredMethod("set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), get.getReturnType());
                    set.invoke(param, get.invoke(data));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new CommonException("请求参数解密失败", e);
        }
    }

    public static void main(String[] args) {
        //需要加密的明文
//        String text = "{\"xm\":\"131231\",\"lxdh\":\"131231\",\"sfzh\":\"131231\",\"xzdqh\":\"131231\",\"pcs\":\"131231\",\"jwh\":\"131231\",\"ryzp\":\"131231\",\"xzdxz\":\"131231\"}";
        String text = "{\"accountName\":\"hanghui\",\"password\":\"Nqj##117521\"}";

        //创建sm2 对象
//        SM2 sm2 = SmUtil.sm2();
//        //这里会自动生成对应的随机秘钥对 , 注意！ 这里一定要强转，才能得到对应有效的秘钥信息
//        byte[] privateKey = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
//        //这里公钥不压缩  公钥的第一个字节用于表示是否压缩  可以不要
//        byte[] publicKey = ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false);
//        //这里得到的 压缩后的公钥   ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(true);
//        // byte[] publicKeyEc = BCUtil.encodeECPublicKey(sm2.getPublicKey());
//        //打印当前的公私秘钥
//        System.out.println("私钥: " + HexUtil.encodeHexStr(privateKey));
//        System.out.println("公钥: " + HexUtil.encodeHexStr(publicKey));

        String publicKey = "0404c69060d28b53b162344d7f0fdcf42d0816feeac1a5b572a98e90ac4283440f103b722c04b30c81673efc23021950b631ef630e5d020ff3ba0ff3c1fad3e48a";
        String privateKey = "0093f815623e3e86e8909e70020b11a77efa5c4e345bb0f2e50f0765aa201724d7";
//        String publicKeyStr = "04509fedbf3d32b8989194f5bc0b7fb5238f95a574352edaf9741b9c2f3ec7f7d22af04cf0a1d9997bef3300d0f24c2eb590239243a3d0de0a1881d91775025ff1";
//        String privateKeyStr = "5422e056fd712952fee0ef7aaa7a08749c3dc39eed7e6fe0e555f601e093e7d6";
        SM2 sm2 = SmUtil.sm2(null, publicKey);
        String s = sm2.encryptHex(text, KeyType.PublicKey);
        System.out.println(s);


        SM2 sm2_1 = SmUtil.sm2(privateKey, null);
        byte[] decrypt = sm2_1.decrypt(s, KeyType.PrivateKey);
        String decryptStr = new String(decrypt);
        System.out.println(decryptStr);
    }
}
