package com.brilliance.isc.common.lock.aop;

import cn.hutool.core.date.StopWatch;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.constant.ErrorCode;
import com.brilliance.isc.vo.manager.SessionUserVo;
import com.brilliance.isc.exception.RestBizException;
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.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class CheckRepeatSubmitAspect {

    private final Logger logger = LoggerFactory.getLogger(CheckRepeatSubmitAspect.class);

    @Resource
    private RedissonClient redissonClient;

    private static final String  PREFIX = "RepeatSubmit";

    private static final String  SEPARATOR = "-";

    private static final Long  LEASE_TIME = 6L;

    @Pointcut("@annotation(com.brilliance.isc.annotation.CheckRepeatSubmit)")
    public void checkRepeatSubmit(){

    }

    @Around("checkRepeatSubmit()")
    public Object repeatSubmitHandler(ProceedingJoinPoint joinPoint){
        SessionUserVo sessionUserVo = SettleContext.getSessionUserVo();
        if (sessionUserVo == null) {
            throw new RestBizException(ErrorCode.BIZ_COMMON_ERROR, "用户未登录!"); 
        }
        String logName = sessionUserVo.getLogName();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        // 获取到的唯一值
        String key = PREFIX + SEPARATOR + logName + SEPARATOR + className + SEPARATOR + methodName;
        logger.info("checkRepeatSubmit:key is ===> "+key);
        RLock lock = redissonClient.getLock(key);
        boolean locked = lock.isLocked();
        logger.info("checkRepeatSubmit:lock status is ===> "+locked);
        if (locked) {
            throw  new RestBizException(ErrorCode.LOCK_SUBMIT_REPEAT,"数据已提交，请勿重复提交!");
        }
        lock.lock(LEASE_TIME, TimeUnit.SECONDS);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        try {
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            logger.error("checkRepeatSubmit: an exception has been throwing in "+className+":"+methodName+"():{}",throwable);
            if(throwable instanceof RestBizException){
                throw (RestBizException) throwable;
            }else {
                throw new RestBizException(ErrorCode.BIZ_COMMON_ERROR, throwable.getMessage());  
            }
        } finally {
            try {
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                    stopWatch.stop();
                    logger.info("checkRepeatSubmit：total run time(seconds) ===> " + stopWatch.getTotalTimeSeconds());
                }
            }catch (Exception e){
                logger.warn("超期锁释放异常，无须关注。");
            }
        }
    }

}
