package com.xxfc.platform.common.aop;

import com.xxfc.platform.common.annotaion.NoRepeatSubmit;
import com.xxfc.platform.common.msg.ApiResult;
import com.xxfc.platform.common.msg.PageApiResult;
import com.xxfc.platform.common.util.RedisLock;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author libin
 * @version 1.0
 * @description
 * @data 2019/7/8 21:04
 */
@Aspect
@Component
@Slf4j
public class NoRepeatSubmitAop {

    @Value("${auth.user.token-header:Authorization}")
    private String tokenHeader;

    private static final String NO_REPEAT_SUBMIT_PREKEY = "no:submit";

    @Autowired
    private RedisLock redisLock;

    @Pointcut("@annotation(noRepeatSubmit)")
    public void noRepeateSubmitExpress(NoRepeatSubmit noRepeatSubmit) {}

    @Around("noRepeateSubmitExpress(noRepeatSubmit)")
    public Object noRepeateSubmitAround(ProceedingJoinPoint proceedingJoinPoint, NoRepeatSubmit noRepeatSubmit) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String uri = request.getRequestURI();
        String token = request.getHeader(tokenHeader);

        String lockKey = String.format("%s%s:%s:%s", StringUtils.isEmpty(noRepeatSubmit.pre()) ? "" : noRepeatSubmit.pre() + ":", NO_REPEAT_SUBMIT_PREKEY, token, uri);
        boolean tryLock = redisLock.tryLock(lockKey, uri, noRepeatSubmit.exptunit(), noRepeatSubmit.timeout());

        Object result = null;
        if (tryLock) {
            log.info("tryLock success, key=【{}】,接口地址:uri=【{}】", lockKey, uri);
            try {
                result = proceedingJoinPoint.proceed();
            } catch (Throwable throwable) {
                log.error(throwable.getMessage(), throwable);
            } finally {
                redisLock.releaseLock(lockKey, uri);
                log.info("releassLock success,key=【{}】,接口地址：uri=【{}】", lockKey, uri);
            }
            return result;
        } else {
            log.info("tryLock fail key=【{}】", lockKey);
            return ApiResult.fail(100001, "获取锁失败");
        }
    }
}
