package com.hzs.common.core.aspect;

import com.hzs.common.core.annotation.RepeatSubmit;
import com.hzs.common.core.constant.CacheToolsConstants;
import com.hzs.common.core.constant.HttpStatus;
import com.hzs.common.core.constant.MemberFieldConstants;
import com.hzs.common.core.constant.msg.MemberMsgConstants;
import com.hzs.common.core.service.RedisService;
import com.hzs.common.core.utils.TransactionUtils;
import com.hzs.common.core.web.domain.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @author: sui q
 * @time: 2022/8/27 14:45
 * @description:防止重复提交的切面类
 * @classname: RepeatSubmitAspectAdvice
 * @package_name: com.hzs.common.core.aspect
 */
@Aspect
@Component
@Slf4j
public class RepeatSubmitAspectAdvice {

    private RedisService redisService;

    @Autowired
    public void setRedisService(RedisService redisService) {
        this.redisService = redisService;
    }

    @Pointcut("@annotation(com.hzs.common.core.annotation.RepeatSubmit)")
    private void requestRepeatCheck() {
        log.info("进入切点");
    }

    @Around(value = "requestRepeatCheck()")
    public Object handleResubmit(ProceedingJoinPoint joinPoint) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        String token = request.getHeader(MemberFieldConstants.TOKEN) == null ? "" :
                request.getHeader(MemberFieldConstants.TOKEN);
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        //获取注解信息
        RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
        int delaySeconds = annotation.delaySeconds();
        // 登陆人从security中获取
        //获取第一个参数
        try {
            //解析参数
            String cacheObject = redisService.getCacheObject(CacheToolsConstants.IDEMPOTENT_TOKEN + token);
            // 验证token是否是由本系统生成的
            // 验证token是否可以加锁，可以加锁说明没有重复提交
            if (!token.equals(cacheObject) || !redisService.lockKeyOnce(cacheObject, delaySeconds)) {
                // 替换翻译
                return AjaxResult.error(TransactionUtils.getContent(MemberMsgConstants.TOKEN_REPEAT_SUBMIT));
//                return AjaxResult.error("请求已经失效，请刷新重试！");
            }
            Object obj = joinPoint.proceed();
            afterReturn(token, obj);
            return obj;
        } catch (Throwable throwable) {
            // 处理异常通知
            log.info("执行异常通知:{}", throwable.getMessage());
            redisService.deleteObjectByKey(token);
            throw new RuntimeException(throwable);
        }
    }

    private void afterReturn(String token, Object obj) {
        if(obj instanceof AjaxResult){
            AjaxResult ajaxResult = (AjaxResult) obj;
            // 成功删除token
            if((Integer) ajaxResult.get(AjaxResult.CODE_TAG) == HttpStatus.SUCCESS){
                redisService.deleteObjectByKey(token);
                redisService.deleteObjectByKey(CacheToolsConstants.IDEMPOTENT_TOKEN + token);
            }else {
                redisService.deleteObjectByKey(token);
            }
        }
    }

}
