package com.philisense.www.aspect;

import com.alibaba.fastjson.JSON;
import com.philisense.www.annotation.repeat.RepeatSubmit;
import com.philisense.www.constant.HttpStatus;
import com.philisense.www.utils.SameUrlDataUtils;
import com.philisense.www.utils.ServletUtils;
import com.philisense.www.utils.StringUtils;
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.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 判断请求url和数据是否和上一次相同，
 * 如果和上次相同，则是重复提交表单。 有效时间为10秒内。
 *
 * @author
 */
@Aspect
@Component
public class RepeatSubmitAspect {

    public final Integer REPEAT_SUBMIT_INTERVAL = 10; // 10s
    public final String REPEAT_SUBMIT_MESSAGE = "不允许重复提交，请稍候再试";

    @Autowired
    private SameUrlDataUtils sameUrlDataUtils;

    /**
     * 令牌自定义标识
     */
    @Value("${jwt.header}")
    private String header;
    
    /**
     * 配置切入点
     */
    @Pointcut("@annotation(com.philisense.www.annotation.repeat.RepeatSubmit)||" +
            "execution(public * com.philisense.www.controller.*.*.insert*(..))||" +
            "execution(public * com.philisense.www.controller.*.*.update*(..))")
    public void repeatSubmitPointcut() {
        // 该方法无方法体,主要为了让同类中其他方法使用此切入点
    }

    /**
     * 配置环绕通知,使用在方法repeatSubmitPointcut()上注册的切入点
     *
     * @param joinPoint join point for advice
     */
    @Around("repeatSubmitPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();

        MethodSignature methodSignature =(MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method pointmethod = methodSignature.getMethod();
        //获取操作
        RepeatSubmit annotation = pointmethod.getAnnotation(RepeatSubmit.class);

        int interval = REPEAT_SUBMIT_INTERVAL;
        String message = REPEAT_SUBMIT_MESSAGE;
        if(StringUtils.isNotNull(annotation)) {
            interval = annotation.interval();
            message = annotation.message();
        }

        // 如果缓存中有这个url视为重复提交
        if (sameUrlDataUtils.isRepeatSubmit(request, interval, header)) {
            Map<String,Object> responsemap = new HashMap<>();
            responsemap.put("success", false);
            responsemap.put("message", message);
            responsemap.put("error", "Duplicate submissions are not allowed, please try again later");
            responsemap.put("status", HttpStatus.ERROR);
            responsemap.put("timestamp", new Date());
            responsemap.put("path", request.getRequestURI());
            ServletUtils.renderString(response, JSON.toJSONString(responsemap));
            return null;
        } else {
            //通过，执行下一步
            Object o = joinPoint.proceed();
            //返回结果
            return o;
        }

    }

}
