package cn.iocoder.yudao.module.system.config.aop;

import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.system.config.poperties.ZnConfigConstant;
import cn.iocoder.yudao.module.system.config.ratelimiter.SystemRateLimiter;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 拦截声明了 {@link SystemRateLimiter} 注解的方法，实现限流操作
 *
 * @author 芋道源码
 */
@Aspect
@Component
@Slf4j
public class SystemRateLimiterAspect {
    private static final Logger logger = LoggerFactory.getLogger(SystemRateLimiterAspect.class);

    @Resource
    private RedisUtil redisUtil;


    @Autowired
    private ZnConfigConstant znConfigConstant;

    @Pointcut("@annotation(cn.iocoder.yudao.module.system.config.ratelimiter.SystemRateLimiter)")
    public void serviceLimit() {

    }

    @Around("serviceLimit()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        if (!znConfigConstant.getOpenRateLimiter()) {
            return joinPoint.proceed();
        }
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SystemRateLimiter systemRateLimiter = method.getAnnotation(SystemRateLimiter.class);
        String key = systemRateLimiter.keyArg();
        int time = systemRateLimiter.time();
        // 获取redis的value
        Integer maxTimes = null;
        Object value = redisUtil.get(key);
        if (value != null) {
            maxTimes = (Integer) value;
        }

        Object obj = null;

        if (maxTimes == null) {
            // 如果redis中没有该ip对应的时间则表示第一次调用，保存key到redis
            redisUtil.set(key, 1, time);
            //这个方法用于执行原来的方法或继续原来的控制流程。
            obj = joinPoint.proceed();
        } else if (maxTimes < systemRateLimiter.count()) {
            // 如果redis中的时间比注解上的时间小则表示可以允许访问,这是修改redis的value时间
            redisUtil.set(key, maxTimes + 1, time);
            //这个方法用于执行原来的方法或继续原来的控制流程。
            obj = joinPoint.proceed();
        } else {
            // 请求过于频繁
//            logger.info("请求过于频繁 ：{}", key);
        }
        return obj;
    }



}
