package com.youchain.DuplicateSubmission;

import com.alibaba.fastjson.JSON;

import com.youchain.exception.BadRequestException;
import com.youchain.utils.RedisUtils;
import com.youchain.utils.RequestHolder;
import com.youchain.utils.SpringContextHolder;
import com.youchain.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Aspect
@Component
public class DuplicateSubmissionAspect {

    // @Around("@annotation(com.example.demo.LogExecutionTime)")表示该环绕通知仅在使用@LogExecutionTime注解的方法上执行
    @Around("@annotation(duplicateSubmission)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint,DuplicateSubmission duplicateSubmission) throws Throwable {

        int value = duplicateSubmission.value();


        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String parm1=getParameter(method, joinPoint.getArgs());
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        String parm=handleParm(request);
        String url=handlerUrl(request);
        RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
        String key=url+"-"+parm1+"-"+parm;
        if(redisUtils.hasKey(key)){
            throw new BadRequestException("操作过快，请稍后重试");
        }
        redisUtils.set(key,"",value);
        // 执行目标方法
        Object result = joinPoint.proceed();
        System.out.println("请求参数为："+key);

        redisUtils.del(key);
        return result;
    }


    private String handleParm( HttpServletRequest request) {
        if (request == null) {
            return "";
        }
        String parm="";
        try {
            parm=request.getQueryString();
        } catch (Exception e) {
            parm="";
            System.out.println("parm获取失败");
        }
        if(parm==null||parm.isEmpty()){
            parm="";
        }
        return parm;
    }

    private String getParameter(Method method, Object[] args) {
        List<Object> argList = new ArrayList<>();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            // 过滤掉不能序列化的类型: MultiPartFile
            if (args[i] instanceof MultipartFile) {
                continue;
            }
            //将RequestBody注解修饰的参数作为请求参数
            RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
            if (requestBody != null) {
                argList.add(args[i]);
            }
            //将RequestParam注解修饰的参数作为请求参数
            RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
            if (requestParam != null) {
                Map<String, Object> map = new HashMap<>(2);
                String key = parameters[i].getName();
                if (!StringUtils.isEmpty(requestParam.value())) {
                    key = requestParam.value();
                }
                map.put(key, args[i]);
                argList.add(map);
            }
        }
        if (argList.isEmpty()) {
            return "";
        }
        return argList.size() == 1 ? JSON.toJSONString(argList.get(0)) : JSON.toJSONString(argList);
    }

    private String handlerUrl( HttpServletRequest request) {
        if (request == null) {
            return "";
        }
        String url="";
        try {
            url=request.getRequestURL().toString();
        } catch (Exception e) {
            url="";
        }
        if(url==null||url.isEmpty()){
            url="";
        }
        return url;
    }
}

