package com.yc.ship.module.trade.framework.aop;

import com.yc.ship.framework.common.util.servlet.ServletUtils;
import com.yc.ship.framework.web.core.util.WebFrameworkUtils;
import com.yc.ship.module.trade.framework.annotation.TradeRateLimit;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * 限流环境 AOP 切面
 */
@Component
@Aspect
@Slf4j
public class TradeRateLimitAspect {
    @Autowired
    private RedisUtils redisUtils;

    /***
     *&#064;Description  拦截所有带 @TradeRateLimit 注解的方法
     *@author qsl
     *&#064;date  2025/8/6 14:29
     */
    @Around("@annotation(rateLimit)")
    public Object handleRateLimit(ProceedingJoinPoint pjp, TradeRateLimit rateLimit) throws Throwable {
        // 获取方法对象
        HttpServletRequest request = ServletUtils.getRequest();
        // 获取 IP 地址
        String ip = ServletUtils.getClientIP(request);
        String key = ip+"_"+rateLimit.name();
        try {
            Long userId = WebFrameworkUtils.getLoginUserId();
            key = ip+"_"+userId+"_"+rateLimit.name();
        }catch (Exception ignore){}
        // 获取限流次数和自定义的 Redis 键
        int limitNum = rateLimit.limitNum();
        int limitTime = rateLimit.limitTime();

        // 限流检查
        boolean isRateLimited = isRateLimited(key, limitNum,limitTime);
        if (isRateLimited) {
            log.error("{}限流次数:{},时间{}", key, limitNum,limitTime);
            throw new RateLimitException("请求过于频繁，请稍后再试");
        }
        return pjp.proceed();
    }

    // 执行 Redis 限流逻辑
    private boolean isRateLimited(String key, int limitNum,int limitTime) {
        String ipKey = "rate_limit:" + key;
        String ipKey2 = "rate_limit_cut:" + key;
        // 获取 IP 请求次数
        if (redisUtils.get(ipKey2) != null) {
            // IP 超过请求次数限制 限制期内
            return true;
        }
        Integer ipRequestCount = redisUtils.getInt(ipKey);
        if (ipRequestCount != null && ipRequestCount >= limitNum) {
            //第一次被限制后 限制5秒内不能请求
            redisUtils.expire(ipKey2, 5, TimeUnit.SECONDS);
            return true;
        }
//        log.error("----key---"+ipKey+"_"+limitTime);
        // 用户请求次数加 1，并设置过期时间
        redisUtils.incr(ipKey, 1);
        redisUtils.expire(ipKey, limitTime, TimeUnit.SECONDS);
        return false; // 未超过请求次数限制
    }

}
