package com.yuchen.saas.park.service.annotation;

import com.yuchen.saas.park.api.dto.third.ThirdRequestDTO;
import com.yuchen.saas.park.api.util.StringUtil;
import com.yuchen.saas.park.api.util.ThirdSignatureUtil;
import com.yuchen.saas.park.service.constant.ThirdCommonConstant;
import com.yuchen.saas.park.service.exception.ThirdBusinessException;
import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.UUID;

/**
 * @Author: baichaojie
 * @CreateTime: 2024/10/30 11:47
 * @Description: 机器人数字签名校验切面
 * @Version: 1.0
 */
@Aspect
@Component
@Slf4j
public class SignatureValidateAspect {


    /**
     * 只切入第三方请求的控制层
     */
    @Pointcut(value = "@annotation(com.yuchen.saas.park.service.annotation.Signature)")
    public void signaturePointcut() {

    }

    /**
     * 方法调用前做校验
     *
     * @param joinPoint 切点
     */
    @Before(value = "signaturePointcut()")
    public void signatureValidate(JoinPoint joinPoint) {
        // 获取注解
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Signature annotation = method.getAnnotation(Signature.class);
        Object[] args = joinPoint.getArgs();
        //int i = 0;

        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();

        ThirdRequestDTO thirdRequestDTO = new ThirdRequestDTO();
        thirdRequestDTO.setClientId(request.getHeader("clientId"));
        if (StringUtil.isEmpty(request.getHeader("clientId"))) {
            throw new RuntimeException("header缺少clientId参数");
        }

        //调用存储第三方设备sn的数据库匹配clientId,如果不存在,就抛异常

        boolean isInDb = judgeThirdDeviceSn(thirdRequestDTO.getClientId());
        if (!isInDb) {
            throw new RuntimeException("设备sn未登记,请先登记");
        }

        if (StringUtil.isEmpty(request.getHeader("timestamp"))) {
            throw new RuntimeException("header缺少timestamp参数");
        }

        thirdRequestDTO.setTimestamp(Long.parseLong(request.getHeader("timestamp")));


        if (StringUtil.isEmpty(request.getHeader("nonce"))) {
            throw new RuntimeException("header缺少nonce参数");
        }
        thirdRequestDTO.setNonce(request.getHeader("nonce"));

        if (StringUtil.isEmpty(request.getHeader("version"))) {
            throw new RuntimeException("header缺少version参数");
        }
        thirdRequestDTO.setVersion(request.getHeader("version"));

        if (StringUtil.isEmpty(request.getHeader("signatureVersion"))) {
            throw new RuntimeException("header缺少signatureVersion参数");
        }
        thirdRequestDTO.setSignatureVersion(request.getHeader("signatureVersion"));

        if (StringUtil.isEmpty(request.getHeader("signature"))) {
            throw new RuntimeException("header缺少signature参数");
        }
        thirdRequestDTO.setSignature(request.getHeader("signature"));

        // 获取请求信息
        String url = request.getRequestURL().toString();
        // 第三方请求json字符串数据
        String thirdData = ThirdFilter.getSignData(request);
        ThirdRequestDTO requestDTO = thirdRequestDTO;
        log.debug("请求地址为：{}；请求参数为：{}", url, thirdData);
        // 数字签名校验
        this.signatureValidate(requestDTO, annotation, url, thirdData);
        // 重放攻击判定
        this.repeatAttackValidate(requestDTO);

//        for (Object arg : args) {
//            if (arg instanceof ThirdRequestDTO) {
//                //i++;
//                // 转换参数
//                RequestAttributes ra = RequestContextHolder.getRequestAttributes();
//                ServletRequestAttributes sra = (ServletRequestAttributes) ra;
//                HttpServletRequest request = sra.getRequest();
//                // 获取请求信息
//                String url = request.getRequestURL().toString();
//                // 第三方请求json字符串数据
//                String thirdData = ThirdFilter.getSignData(request);
//                ThirdRequestDTO requestDTO = (ThirdRequestDTO) arg;
//                log.debug("请求地址为：{}；请求参数为：{}", url, thirdData);
//                // 数字签名校验
//                this.signatureValidate(requestDTO, annotation, url, thirdData);
//                // 重放攻击判定
//                this.repeatAttackValidate(requestDTO);
//            }
//        }

//        if(i==0){
//            throw new RuntimeException("header缺少参数");
//        }

    }

    /**
     * 判断header里携带的clientId是否在数据库第三方设备表里
     *
     * @param clientId
     * @return 如果不存在, 返回false,
     * @return 如果存在, 返回true
     */
    private boolean judgeThirdDeviceSn(String clientId) {
        Boolean b = false;
        //调用数据库查询判断


        return b;
    }

    /**
     * 数字签名校验,thirdData没有参与签名
     *
     * @param requestDTO 请求头
     */
    private void signatureValidate(ThirdRequestDTO requestDTO, Signature annotation, String url, String thirdData) {
        // 参数校验
        String clientId = requestDTO.getClientId();//b72d777ad6f409e1
        String version = requestDTO.getVersion();
        String signatureVersion = requestDTO.getSignatureVersion();
        String annotationSignatureVersion = annotation.version();

        if (!annotationSignatureVersion.equals(signatureVersion)) {
            throw new ThirdBusinessException(ThirdCommonConstant.ResponseCode.PARAMS_ERROR, "数字签名算法版本号不一致！", UUID.randomUUID().toString());
        }
        if (!"1.0".equals(version)) {
            throw new ThirdBusinessException(ThirdCommonConstant.ResponseCode.PARAMS_ERROR, "API版本号不一致！", UUID.randomUUID().toString());
        }

        // 第三方签名字符串
        String signature = requestDTO.getSignature();

        //进行签名校验
        String clientSecret = "1c544f49fe54d137";//获取秘钥
        String signMethod = url.split("/")[url.split("/").length - 1];
        String signatureValidate;

        // 数字签名请求参数
        // 第三方请求参数为空，则签名不带参数，否则需要带请求参数进行签名
        signatureValidate = ThirdSignatureUtil.genSignature(clientId, clientSecret, version, requestDTO.getTimestamp().toString(), requestDTO.getNonce(), signatureVersion);

        log.debug("第三方签名为：{}；我方签名为：{}", signature, signatureValidate);

        if (!signature.equals(signatureValidate)) {
            throw new ThirdBusinessException(ThirdCommonConstant.ResponseCode.SIGNATURE_FAIL, "数字签名存在异常！", UUID.randomUUID().toString());
        }
    }

    /**
     * 重放攻击判定
     *
     * @param requestDTO 请求头
     */
    private void repeatAttackValidate(ThirdRequestDTO requestDTO) {
        Long timestamp = requestDTO.getTimestamp();
        Long now = System.currentTimeMillis();
        long fiveMin = 5L * 60L * 1000L;
        String nonce = requestDTO.getNonce();
        if (now - timestamp < fiveMin) {
            // 小于五分钟内校验随机数
            String nonceValidate = ThirdCommonConstant.nonceValidate;
            if (nonce.equals(nonceValidate)) {
                // 随机数重复为重放
                throw new ThirdBusinessException(ThirdCommonConstant.ResponseCode.FAIL, "请勿重复请求！", UUID.randomUUID().toString());
            } else {
                // 正常请求时需要更新nonce
                ThirdCommonConstant.nonceValidate = nonce;
            }
        } else {
            // 正常请求时需要更新nonce
            ThirdCommonConstant.nonceValidate = nonce;
        }
    }
}


