package com.usky.issue.annotation;

import com.alibaba.fastjson.JSONObject;
import com.usky.common.core.bean.ApiResult;
import com.usky.common.core.utils.StringUtils;
import com.usky.issue.mapper.SpProjectConfigMapper;
import com.usky.issue.service.util.SignUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;

@Aspect   //定义一个切面
@Configuration
@Slf4j
public class CheckSignAspect {
    @Autowired
    private SpProjectConfigMapper spProjectConfigMapper;
    @Value("${sign.expireTime}")
    private long expireTime;//接口签名验证超时时间
    @Value("${sign.secretKey}")
    private String secretKey;//接口签名唯一密钥

    // 定义切点Pointcut
    @Pointcut("@annotation(com.usky.issue.annotation.CheckSign)")
    public void excudeService() {
    }

    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        log.info("开始验证签名");
        try {
            ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = Objects.requireNonNull(sra).getRequest();
            Object[] args = joinPoint.getArgs();
            String originalValue = (String) args[0];
            JSONObject requestBody = JSONObject.parseObject(originalValue);
            String timestamp = requestBody.get("timestamp").toString();//获取timestamp参数
            String sign = requestBody.get("sign").toString();//获取sign参数
            String appKey = request.getHeader("appKey");//获取appKey参数
            if (StringUtils.isBlank(timestamp) || StringUtils.isBlank(sign) || StringUtils.isBlank(appKey)) {
                return ApiResult.success("timestamp和sign、appKey参数不能为空");
            }
            long requestTime = Long.valueOf(timestamp);
            long now = System.currentTimeMillis() / 1000;
            // 请求发起时间与当前时间超过expireTime，则接口请求过期
            if (now - requestTime > expireTime) {
                return ApiResult.success("接口请求过期");
            }

            String generatedSign = generatedSignature(request, timestamp,appKey);
            if (!generatedSign.equals(sign)) {
                return ApiResult.success("签名校验错误");
            }
            String companyCode = spProjectConfigMapper.getCompanyCode(appKey);
            StringBuilder newString = new StringBuilder(originalValue);
            newString.insert(newString.lastIndexOf("}"), ",\"companyCode\":\""+companyCode+"\"");
            args[0] = newString.toString();
            Object result = joinPoint.proceed(args);
            return result;
        } catch (Throwable t) {
            return ApiResult.success("签名校验异常");
        }

    }

    //获取请求参数并生成签名
    private String generatedSignature(HttpServletRequest request, String timestamp,String appKey) {
        //获取RequestBody参数，此处需要配合过滤器处理request后才能获取
        String bodyParam = null;
        if (request instanceof ContentCachingRequestWrapper) {
            bodyParam = new String(((ContentCachingRequestWrapper) request).getContentAsByteArray(), StandardCharsets.UTF_8);
        }

        //获取RequestParam参数
        Map<String, String[]> requestParameterMap = request.getParameterMap();

        //获取PathVariable参数
        ServletWebRequest webRequest = new ServletWebRequest(request, null);
        Map<String, String> requestPathMap = (Map<String, String>) webRequest.getAttribute(
                HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);

        return SignUtil.sign(bodyParam, requestParameterMap, requestPathMap, secretKey, timestamp,appKey);
    }

}
