package com.YuyeTech.TPlat.aspect;

import com.YuyeTech.TPlat.exception.AuthorizeException;
import com.google.common.collect.Maps;

import com.YuyeTech.TPlat.constant.CookieConstant;
import com.YuyeTech.TPlat.constant.RedisConstant;
import com.YuyeTech.TPlat.enums.ResultEnum;
import com.YuyeTech.TPlat.utils.CookieUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
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.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * AOP 切面，拦截器
 * 现在 在 filter 里面 做token 验证
 * @author:slambb
 * @date:2019/12/13
 */
@Aspect
@Component
@Slf4j
public class AuthorizeAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;
    //"&& !execution(public * com.YuyeTech.TPlat.controller.BackstageBLEDeviceController.*(..))"
    @Pointcut("execution(public * com.YuyeTech.TPlat.controller.Backstage*.*(..))" +
            "&& !execution(public * com.YuyeTech.TPlat.controller.BackstageManagerController.*(..))")
    public void verifyAuthorize() {}

    @Before("verifyAuthorize()")
    public void doVerifyAuthorize() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        //查询cookie
        Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
        if (cookie == null) {
//            log.warn("【登录校验】Cookie中查不到token");
            throw new AuthorizeException(ResultEnum.COOKIE_PARAM_ERROR.getCode(),
                    ResultEnum.COOKIE_PARAM_ERROR.getMessage());
        }

        //去redis里查询
        String tokenValue = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue()));
        if (StringUtils.isEmpty(tokenValue)) {
//            log.warn("【登录校验】Redis中查不到token");
            throw new AuthorizeException(ResultEnum.TOKEN_IS_ILLEGAL.getCode(),
                    ResultEnum.TOKEN_IS_ILLEGAL.getMessage());
        }
    }

    //切点
    // execution(public * com.slambb.smallshop.controller.UserInfoController.*(..))
//    @Pointcut("execution(public * com.slambb.smallshop.controller.UserInfoController.*(..))")
    public void verify() {

    }

    //在切点做拦截
//    @Before("verify()")
    public void doVerify(JoinPoint joinPoint) throws Exception {

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.info("请求地址:" + request.getRequestURL().toString());
        log.info("请求方式:" + request.getMethod());
        log.info("请求类方法:" + joinPoint.getSignature());
        log.info("请求类方法参数:" + Arrays.toString(joinPoint.getArgs()));
        //获取传入目标方法的参数
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            args[i] = 1;
            System.out.println("第" + (i+1) + "个参数为:" + args[i]);
        }
        System.out.println("被代理的对象:" + joinPoint.getTarget());
        System.out.println("代理对象自己:" + joinPoint.getThis());


//        Object openid =redisTemplate.opsForHash().get(String.format(RedisConstant.TOKEN_PREFIX,token),"openid");
//        log.info("openid ====",openid);
//        // 用户信息校验
//        if (StringUtils.isEmpty(openid)) {
//            log.warn("【登录校验】 Redis 中查找不到token 对应的信息（openid）");
//            throw new AuthorizeException();
//        }



//        //获取到请求后，查询cookie
//        Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN);
//        if(cookie == null){
//            log.warn("【登录校验】 cookie 中查不到token");
//            throw  new AuthorizeException();
//        }
//        log.info("请求的 cookie",cookie);
//
//        //如果存在，去redis查询对应的token
//        String tokenValue = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX,cookie.getValue()));
//        if(StringUtils.isEmpty(tokenValue)){
//            log.warn("【登录校验】 Redis 中查找不到token");
//            throw new AuthorizeException();
//        }
    }

//    @Around("verify()")
    public Object aroundVerify(ProceedingJoinPoint pjd){

        Object result = null;
        Object[] args = pjd.getArgs();
        for (int i = 0; i < args.length; i++) {
            args[i] = 1;
            System.out.println("第==" + (i+1) + "个参数为:" + args[i]);
        }
        try {
            //前置通知
            System.out.println("目标方法执行前...");
            //执行目标方法
            //result = pjd.proeed();
            //用新的参数值执行目标方法
//            Map<String,Object> map = new HashMap<>();
//            map.put("userId",123);
//            new Object[]{"1577343249102947918","111"}
            //获取RequestAttributes
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            //从获取RequestAttributes中获取HttpServletRequest的信息
            HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
            //如果要获取Session信息的话，可以这样写：
            //HttpSession session = (HttpSession) requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
            Enumeration<String> enumeration = request.getParameterNames();
            Map<String,String> parameterMap = Maps.newHashMap();
            while (enumeration.hasMoreElements()){
                String parameter = enumeration.nextElement();
                parameterMap.put(parameter,request.getParameter(parameter)+1);
            }
            log.info("enumeration={}",parameterMap);
            result = pjd.proceed();

            //返回通知
            System.out.println("目标方法返回结果后...");
        } catch (Throwable e) {
            //异常通知
            System.out.println("执行目标方法异常后...");
            throw new RuntimeException(e);
        }
        //后置通知
        System.out.println("目标方法执行后...");

        return result;
    }
}
