package com.ho.td.config;

import com.alibaba.fastjson.JSON;
import com.ho.common.tools.constant.CommonConstant;
import com.ho.common.tools.constant.RedisKeyConstant;
import com.ho.common.tools.entity.SimpleUser;
import com.ho.common.tools.entity.UserDetailRespVO;
import com.ho.common.tools.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.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.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.Method;

/**
 * 模块切面
 * 目前实现日志和token校验
 */
@Aspect
@Component
@Slf4j
public class TdServiceAspect {

    @Autowired
    RedisService redisService;

    /**
     * 此处的切点是注解的方式
     * 只要出现 @LogAnnotation注解都会进入
     * 改为切入点是controller,不然日志记录不清晰,只有LogAnnotation才入库
     */
    //@Pointcut("@annotation(com.ho.common.tools.annotation.LogAnnotation)")
    @Pointcut("execution(* com.ho.*.controller.*.*(..))")
    public void pointCut() {

    }

    /**
     * 环绕增强,相当于MethodInterceptor
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        ServletRequestAttributes servletAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletAttributes.getRequest();
        UserDetailRespVO userDetail = null;
        SimpleUser simpleUser = null;
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //是否是token忽略
        //TokenIgnore tokenIgnoreAnnotation = method.getAnnotation(TokenIgnore.class);
        //是否大屏token
        //LargeScreenToken largeScreenToken = method.getAnnotation(LargeScreenToken.class);
        String token = request.getHeader(RedisKeyConstant.User.ACCESS_TOKEN);
        //log.info("token:" + token);
        String url = request.getRequestURL().toString();
        String className = point.getTarget().getClass().getName();
        String methodName = signature.getName();
        log.info("请求url:{} ,method:{}, 开始时间: {}", url, method, beginTime);

        //请求参数
        String params = null;
        try {
            //请求的参数
            Object[] args = point.getArgs();
            //MultipartFile类型的跳过转Json
            if (args != null && args.length > 0 && args[0] != null) {
                String simpleClassName = args[0].getClass().getSimpleName();
                log.info("SimpleClassName:" + simpleClassName);
                //不包含文件类型才打印日志
                if (!StringUtils.isBlank(simpleClassName) && !simpleClassName.contains("Multipart")) {
                    params = JSON.toJSONString(args[0]);
                    //log.info("params:" + params);
                    log.info("params:" );
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        log.info("methodName:{}, className:{}", methodName, className);
        //执行目标方法
        //执行方法
        Object result = point.proceed();
        //方法执行结果
        //log.info("返回:" + JSON.toJSONString(result));
        //执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        log.info("耗时:{}, url:{},param:{}", time, url ,null);
        if (time > CommonConstant.timeoutMilliSeconds) {
            log.error("接口超时: 耗时:{} ,url:{}",time, url);
        }
        return result;
    }
}
