package com.cpop.core.aspect;

import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.R;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
import com.cpop.core.utils.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.crypto.Cipher;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @author DB
 * @version 1.0.0
 * @since 2024-01-16 10:31
 */
@Aspect
@Component
@Slf4j
public class SimpleSignatureCheckAspect {

    @Autowired
    private RsaUtils rsaUtils;

    private static final Map<String, String[]> APP_IDS = new HashMap<String, String[]>() {{
        //果酱内部
        put("1747095325571944448", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkPn6JRxgY3/cxyeEQ3xETlI6tcsq4d2GGrgD2pnQ8Db2vaSCEu3k4cV92/HjmoggA09A7cepurO6xeFwya9C8c1YD4UHJQ13MPlKIskDmoc/ZUyklVQKVp60pvi/BpuhECt6LksHu9Yz2ECUBiFXDd2Pgju41Oiu6joIJylWdbUkhTesOs/XnPCUjWw2kQzhpcmoMZwlgneuvGXO72OhI2FD5QTHA00UbnbtzM3hk9cQNRxak+sNzKkv4AOZy5uTjHXVdYcUUwDc7XbuWN/E40tzbyWmoZSuXPt80vOk+KgCEOK+sfPy6YPgxAYh4NOk59qA4x1ZaYSJsLRNo1c/OwIDAQAB",
                "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCQ+folHGBjf9zHJ4RDfEROUjq1yyrh3YYauAPamdDwNva9pIIS7eThxX3b8eOaiCADT0Dtx6m6s7rF4XDJr0LxzVgPhQclDXcw+UoiyQOahz9lTKSVVApWnrSm+L8Gm6EQK3ouSwe71jPYQJQGIVcN3Y+CO7jU6K7qOggnKVZ1tSSFN6w6z9ec8JSNbDaRDOGlyagxnCWCd668Zc7vY6EjYUPlBMcDTRRudu3MzeGT1xA1HFqT6w3MqS/gA5nLm5OMddV1hxRTANztdu5Y38TjS3NvJaahlK5c+3zS86T4qAIQ4r6x8/Lpg+DEBiHg06Tn2oDjHVlphImwtE2jVz87AgMBAAECggEABg36jWw29lDTtpmG446gB6lVfFwkyVQIEruWpZ2A5VdWTKs/J205/tfRnsrmV4DR3XGE46lQBFUXOsZkgHfKUvDheZxzpO+AB9KRbwx4Ew8M7b0aroXY/K8aGlMPH0aGnndCXgaSJx0WAzUHOY5Q5WpYYPb/jBy/mVadGo2WZ8n9cMQQSVwdVFxsGOHckPQePyK41fsjQ6A7pNiW3ErK5TCQ18gimLAbjBeUDj5NKfe8P6o65uETkRBPE+ZL6O95hueqj7FU/8LtBFVXCFmpYLDa0BBRxZCgJP94lnS/GIo2qYkVMJh4fThWh6ZxvscggaWmVPGqhP2zzSDQup+A+QKBgQDtKD5ZdG5KeDC9jMn3HQGYAf8aiNVx0KNxpCn19uRrclNgaEFPPLj/6yWeclqPOAqzk4AGQ+MaMEQzTmHOP7O411jIgX2Ki2D9OilZjr+kObdGoekWGzZKPm38EqP+Z9oAJxNGDBkUe1iH/DUoLGgp1mt19cZn1pPgdR9vsmZwxQKBgQCcfskmHrt3NltXrOzwV3PWwelsA+E+DVn3N9N9+V8ETs0pIxFAg6LuDVxVQziLe2wApp3dy8b/efxnRUYmiFDBUxKf9CQJcZTDncHO/wASObEHlUqcIkBM9Vcy8EMovKSNrNnJHcvNV7zQaRHZshft2rPKnUaIMb0M3H6GokHv/wKBgBc4lopJxTbTd+pHa8sfcvWAVIszlLq1NBu/eEBWMV1370QEUUjB6FdenetaxRU65olYyvNSGF2LFlJzvU3lnOJfa5kOXM2BAjkpRb04JfmdkR2AYwNAHNu+KyTAaoBRiN309YUpUBdaUHvYLRhG6NgX36PIMeoe75HNxgs4y6EFAoGAcvyNm97U68Ea2I8NAYOgb9nHQ0COjeONiSKR2WwTrryf7mv/zyFp4/QZNeTQdVxYfRnvwPpr22esV80EwGdEvuflNXZTzESShDE0KH4hdULCmsnNKm/YQzO5wIndLt99IUQyOZ4VE2o2KAQrw4MiJfieRm/NVWEGgZ65sP8j580CgYEA2iNWW8jkLQhyPwOG4EztXmoTlCJUcwCmgjnL4dlRzAhsCooY+saXG0Q4GlRTJtpgXNM7kFGgAPjBSk57u6xh5I0/Tet8SWagNC2zLTcP2Bk1y2HtjWG+mSHAGEcth6etgnZgrU5daIVRJyTfslYX0i7x6o5EnCzJV0ftIBYstZ4="});
        //数币
        put("1688842965582499840", new String[]{"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"});
    }};

    @Pointcut("@annotation(com.cpop.core.annontation.SimpleSignatureCheck)")
    public void simpleSignatureCheck() {}

    /**
     * 前置通知
     * @author DB
     * @since 2024/1/16
     */
    @Before(value = "simpleSignatureCheck()")
    public void beforePointcut() {
        //获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //从获取RequestAttributes中获取HttpServletRequest的信息
        assert requestAttributes != null;
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        assert request != null;
        String signature = request.getHeader("signature");
        if (StringUtils.isBlank(signature)){
            throw new ServiceException("签名为空,请核实签名");
        }
        String appId = request.getHeader("appId");
        if (StringUtils.isBlank(appId)){
            throw new ServiceException("appId为空,请核实签名");
        }
        String dateTime = request.getHeader("dateTime");
        if (StringUtils.isBlank(dateTime)){
            throw new ServiceException("时间为空,请核实签名");
        }
        String decrypt = rsaUtils.decrypt(signature, stringToKey(APP_IDS.get(appId)[1]));
        String sign = appId + dateTime;
        String md5DigestAsHex = DigestUtils.md5DigestAsHex(sign.getBytes());
        if (!StringUtils.equals(md5DigestAsHex, decrypt)) {
            throw new ServiceException("签名匹配失败,请核实签名");
        }
    }

    /**
     * 环绕通知,不做处理
     * @author DB
     * @since 2024/1/16
     * @param joinPoint 请求
     * @return Object
     */
    @Around("simpleSignatureCheck()")
    public Object aroundPointcut(ProceedingJoinPoint joinPoint) throws Throwable {
        return joinPoint.proceed(joinPoint.getArgs());
    }

    /**
     * 异常通知：目标方法发生异常的时候执行以下代码，此时返回通知不会再触发
     * value 属性：绑定通知的切入点表达式。可以关联切入点声明，也可以直接设置切入点表达式
     * pointcut 属性：绑定通知的切入点表达式，优先级高于 value，默认为 ""
     * throwing 属性：与方法中的异常参数名称一致，
     *
     * @param ex：捕获的异常对象，名称与 throwing 属性值一致
     */
    @AfterThrowing(pointcut = "simpleSignatureCheck()", throwing = "ex")
    public Object aspectAfterThrowing(JoinPoint jp, Exception ex) {
        String methodName = jp.getSignature().getName();
        if (ex instanceof ServiceException) {
            log.error("【异常通知】" + methodName + "方法算术异常（ArithmeticException）：" + ex.getMessage());
            return R.fail(ex.getMessage());
        } else {
            log.error("【异常通知】" + methodName + "方法异常：" + ex.getMessage());
            return R.fail("签名不合法");
        }

    }

    private PrivateKey stringToKey(String stringKey) {
        //Java原生base64解码
        byte[] priKey = Base64.getDecoder().decode(stringKey);
        //创建PKCS8编码密钥规范
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
        //返回转换指定算法的KeyFactory对象
        KeyFactory keyFactory = null;
        try {
            keyFactory = KeyFactory.getInstance("RSA");
            //根据PKCS8编码密钥规范产生私钥对象
            return keyFactory.generatePrivate(pkcs8KeySpec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
    }

}
