package com.ssj.framework.core.security;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import com.ssj.framework.core.util.StringUtil;
import org.apache.commons.lang3.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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.ssj.framework.core.security.annotation.IgnoreSecurity;
import com.ssj.framework.core.security.annotation.ModifySecurity;
import com.ssj.framework.core.security.exception.RequestsException;
import com.ssj.framework.core.security.exception.TokenException;
import com.ssj.framework.core.security.manager.TokenManager;


/**
 * 
 * 类名称：SecurityAspect<br>
 * 类描述：用于检查 token 的切面<br>
 * @version v1.0
 *
 */
@Aspect
@Component
public class SecurityAspect {
	private static final Logger logger = LoggerFactory.getLogger(SecurityAspect.class);
	@Autowired
	private TokenManager tokenManager;
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
	public void methodPointcut(){}
    /**
	 * 拦截器具体实现
	 * @param pjp
	 * @return JsonResult（被拦截方法的执行结果，或需要登录的错误提示。）
	 */
	@Around("methodPointcut()") //指定拦截器规则；也可以直接把“execution(* com.xjj.........)”写进这里
	public Object Interceptor(ProceedingJoinPoint pjp)throws Throwable{
		MethodSignature signature = (MethodSignature) pjp.getSignature();
		Method method = signature.getMethod(); //获取被拦截的方法
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		if (method.isAnnotationPresent(IgnoreSecurity.class)  ) {
			logger.info("直接过滤url：{}", request.getRequestURI());
			return pjp.proceed();
		}

//		String methodName = method.getName(); //获取被拦截的方法名
	//	logger.info("请求getRequestURI：{}",  request.getRequestURI());
	//	logger.info("请求getContextPath：{}",  request.getContextPath());
		String url = request.getRequestURI().replaceFirst(request.getContextPath(), "");
		logger.info("请求url：{}", url);
		if ( !StringUtils.startsWith(url, "/wxapi/") && !StringUtils.startsWith(url, "/api/")) {
            return pjp.proceed();
        }
		String token = StringUtils.isBlank(request.getHeader("accessToken")) ? request.getParameter("accessToken") : request.getHeader("accessToken");

	//	logger.info("请求方法：{}", methodName);
		logger.info("请求token：{}", token);
		// 检查 token 有效性
		if (token == null || !tokenManager.checkToken(token)) {
			String message = String.format("token [%s] is invalid", token);
			//失效标识
			String key = "invalid_reason_" + token;
			String reason = tokenManager.getString(key);
			//reason为“1”：被强制下线；reason为“2”：被超级管理员挤下线；reason为“3”：资料正在审核中，请重新登录；
			if (StringUtil.isNotBlank(reason)) {
				message += ("，失效原因为：{" + reason + "}");
				tokenManager.delString(key);
			}
			throw new TokenException(message);
		}
        if(method.isAnnotationPresent(ModifySecurity.class)){
            String requestsNum = tokenManager.getString(token+url);
            if(requestsNum!=null){
                String message = String.format("请求太频繁 [%s] 请稍后", token+url);
                throw new RequestsException(message);
            }
            tokenManager.setString(token+url, "1",2);
        }
        // 调用目标方法
        Object obj = pjp.proceed();
//        tokenManager.delString(token + url);
        return obj;
	}
}
