package com.seer.teach.common.advice;

import com.seer.teach.common.annotation.RepeatSubmit;
import com.seer.teach.common.exception.RepeatSubmitException;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
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.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

@Slf4j
@Aspect
@Component
public class RepeatSubmitAspect {

    private static final String REDIS_KEY_PREFIX = "SUBMIT_LOCK:";

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Value("${sa-token.token-name:token}")
    private String Authorization;

    @Around("@annotation(repeatSubmit)")
    public Object process(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

        // 生成唯一锁定键
        String lockKey = buildLockKey(joinPoint, request, repeatSubmit.keyType());

        // 检查是否重复提交
        if (isRepeatSubmit(lockKey, repeatSubmit.interval()))  {
            throw new RepeatSubmitException(repeatSubmit.message());
        }

        try {
            // 执行原方法
            return joinPoint.proceed();
        } finally {
            //redisTemplate.delete(lockKey);
            //等待redis中的key自动过期
        }
    }

    private String buildLockKey(ProceedingJoinPoint joinPoint, HttpServletRequest request, RepeatSubmit.KeyType keyType) {
        String uri = request.getRequestURI();
        String token = request.getHeader(Authorization);

        switch (keyType) {
            case TOKEN:
                return REDIS_KEY_PREFIX + token + ":" + uri;

            case PARAMS:
                String paramsHash = DigestUtils.md5DigestAsHex(
                        Arrays.toString(joinPoint.getArgs()).getBytes()
                );
                return REDIS_KEY_PREFIX + uri + ":" + paramsHash;

            default:
                throw new IllegalArgumentException("不支持的Key类型");
        }
    }

    private boolean isRepeatSubmit(String key, long interval) {
        // 使用setIfAbsent实现原子操作
        Boolean result = redisTemplate.opsForValue().setIfAbsent(
                key,
                String.valueOf(System.currentTimeMillis()),
                interval,
                TimeUnit.MILLISECONDS
        );
        // 已存在返回true（重复提交）
        return result == null || !result;
    }
}