package com.kexue.skills.aspect;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.kexue.skills.annotation.PreventDuplicateSubmission;
import com.kexue.skills.exception.BizException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

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

/**
 * @author 维哥
 * @Description
 * @create 2025-02-25 15:33
 */
@Aspect
@Component
public class PreventDuplicateSubmissionAspect {

    private static final Cache<String, Long> requestCache = CacheBuilder.newBuilder()
            .expireAfterWrite(1, TimeUnit.MINUTES) // 缓存1分钟
            .build();

    // 处理方法级别注解
    @Around("@annotation(com.kexue.skills.annotation.PreventDuplicateSubmission)")
    public Object preventDuplicateSubmissionMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        return preventDuplicateSubmissionImpl(joinPoint);
    }
    
    // 处理类级别注解
    @Around("@within(com.kexue.skills.annotation.PreventDuplicateSubmission)")
    public Object preventDuplicateSubmissionClass(ProceedingJoinPoint joinPoint) throws Throwable {
        return preventDuplicateSubmissionImpl(joinPoint);
    }
    
    // 实际的防重复提交逻辑
    private Object preventDuplicateSubmissionImpl(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String key = generateKey(request, joinPoint.getSignature().toShortString());
        
        // 从joinPoint获取方法签名和注解
        org.aspectj.lang.reflect.MethodSignature signature = (org.aspectj.lang.reflect.MethodSignature) joinPoint.getSignature();
        
        // 先从方法上获取注解
        PreventDuplicateSubmission preventDuplicateSubmission = signature.getMethod().getAnnotation(PreventDuplicateSubmission.class);
        
        // 如果方法上没有，再从类上获取
        if (preventDuplicateSubmission == null) {
            preventDuplicateSubmission = (PreventDuplicateSubmission)signature.getDeclaringType().getAnnotation(PreventDuplicateSubmission.class);
        }
        
        // 确保注解存在
        if (preventDuplicateSubmission == null) {
            throw new BizException("无法获取PreventDuplicateSubmission注解");
        }

        Long lastRequestTime = requestCache.getIfPresent(key);
        long currentTime = System.currentTimeMillis();

        if (lastRequestTime != null && (currentTime - lastRequestTime) < preventDuplicateSubmission.timeout()) {
            throw new BizException("瞬间操作过于频繁，请稍后再试");
        }

        requestCache.put(key, currentTime);
        return joinPoint.proceed();
    }

    private String generateKey(HttpServletRequest request, String methodSignature) {
        return request.getSession().getId() + ":" + methodSignature;
    }
}