package com.lesingle.common.interceptor;

import com.lesingle.common.annotation.RateLimit;
import com.lesingle.common.result.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.concurrent.TimeUnit;

/**
 * 速率限制拦截器
 * 基于 Redis 实现滑动窗口限流
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RateLimitInterceptor implements HandlerInterceptor {

    private final StringRedisTemplate redisTemplate;
    private final ObjectMapper objectMapper;

    private static final String RATE_LIMIT_PREFIX = "rate_limit:";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod handlerMethod)) {
            return true;
        }

        RateLimit rateLimit = handlerMethod.getMethodAnnotation(RateLimit.class);
        if (rateLimit == null) {
            return true;
        }

        String key = buildKey(request, rateLimit);
        String redisKey = RATE_LIMIT_PREFIX + key;

        // 获取当前计数
        String countStr = redisTemplate.opsForValue().get(redisKey);
        long currentCount = countStr != null ? Long.parseLong(countStr) : 0;

        if (currentCount >= rateLimit.permits()) {
            log.warn("接口速率限制触发：key={}，已请求 {} 次，限制 {} 次", key, currentCount, rateLimit.permits());
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(429);
            response.getWriter().write(objectMapper.writeValueAsString(
                    Result.error(429, "请求过于频繁，请稍后再试")));
            return false;
        }

        // 增加计数
        Long newCount = redisTemplate.opsForValue().increment(redisKey);
        if (newCount != null && newCount == 1) {
            // 首次请求，设置过期时间
            redisTemplate.expire(redisKey, rateLimit.duration(), rateLimit.timeUnit());
        }

        return true;
    }

    /**
     * 构建限流 key
     */
    private String buildKey(HttpServletRequest request, RateLimit rateLimit) {
        String identity;
        if ("user".equals(rateLimit.key())) {
            // 基于 User-ID（需要认证后才有）
            identity = request.getHeader("X-User-Id");
            if (identity == null) identity = request.getRemoteAddr();
        } else {
            // 基于 IP
            identity = getClientIp(request);
        }
        return request.getMethod() + ":" + request.getRequestURI() + ":" + identity;
    }

    /**
     * 获取客户端真实 IP
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 多级代理取第一个
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }
}
