package com.yeejoin.precontrol.common.aop;

import com.yeejoin.precontrol.common.utils.PlatformUtils;
import com.yeejoin.precontrol.common.utils.RedisUtil;
import com.yeejoin.precontrol.common.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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.core.annotation.Order;
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 java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
 * @description:
 * @author: duanwei
 * @date: 2020-08-03 13:56
 **/
@Aspect
@Component("controllerAopPrecontrol")
@Order(4)
@Slf4j
public class ControllerAop {

    @Autowired
    protected HttpServletRequest request;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    PlatformUtils platformUtils;

    List<String> whiteUrl = new ArrayList<>();

    //白名单
    {
        whiteUrl.add("/precontrol/safe/mobile/login");
        whiteUrl.add("/precontrol/safe/mobile/register");
        whiteUrl.add("/precontrol/safe/mobile/register/history");
        whiteUrl.add("/precontrol/safe/getAuthCode");
        whiteUrl.add("/precontrol/project-qrcode/getPrCodeInfo");
        whiteUrl.add("/precontrol/safe/checkToken");
        whiteUrl.add("/precontrol/echo");
        whiteUrl.add("/precontrol/project/save");
    }

    /**
     * 获取线程副本
     */
    ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Pointcut("execution(public * com.yeejoin.precontrol.controller.*.*(..))")
    public void weblog() {
    }

    @Before("weblog()")
    public void doBefore(JoinPoint joinPoint) throws IllegalAccessException {
        // 获取请求报文头部元数据
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        // 获取请求对象
        HttpServletRequest request = requestAttributes.getRequest();
        String requestUri = request.getRequestURI();
        

        Boolean isAopCheck = true;
        for (String url : whiteUrl) {
            if (url.contains(requestUri)) {
                isAopCheck = false;
            }
        }
        if (isAopCheck && platformUtils.isAutoSetOrgCode()) {
            // 填充项目部id
            setOrgCode(joinPoint);
        }
        // 记录控制器执行前的时间毫秒数
        startTime.set(System.currentTimeMillis());
        log.info("");
        log.info("==================前置通知执行开始==================");
        log.info("url:" + request.getRequestURL());
        log.info("method:" + request.getMethod());
        log.info("ip:" + request.getRemoteAddr());
        log.info("class_method:" + joinPoint.getSignature().getDeclaringTypeName() + "."
                + joinPoint.getSignature().getName());
        log.info("args:" + Arrays.toString(joinPoint.getArgs()));
        log.info("==================前置通知执行结束==================");
    }

    @AfterReturning(returning = "ret", pointcut = "weblog()")
    public void doAfter(Object ret) {
        log.info("=================后置通知执行开始===================");
        if (ret != null) {
            log.info("响应结果:" + ret.toString());
        }
        log.info("方法请求时间:" + (System.currentTimeMillis() - startTime.get()));
        log.info("=================后置通知执行结束===================");
        log.info("");
        startTime.remove();
    }

    /**
     * 填充前置属性值
     *
     * @param joinPoint
     * @throws IllegalAccessException
     */
    private void setOrgCode(JoinPoint joinPoint) throws IllegalAccessException {
        Object[] args = joinPoint.getArgs();
        if (StringUtil.isNotEmpty(args)) {
            // 尝试获取项目部id
            String orgCode = platformUtils.getOrgCode();
            if (StringUtil.isNotEmpty(orgCode)) {
                for (Object arg : args) {
                    // 判断类型
                    if (arg != null) {
                        Class<?> aClass = arg.getClass();
                        if (aClass instanceof Object) {
                            // 反射父类属性
                            Field[] allFields = FieldUtils.getAllFields(aClass);
                            for (Field allField : allFields) {
                                if ("orgCode".equals(allField.getName())) {
                                    if (allField != null) {
                                        allField.setAccessible(true);
                                        allField.set(arg, orgCode);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

}
