package com.nokia.domainb.config;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 日志配置
 *
 */
@Aspect
@Component
@Slf4j
public class LogAspectConfig
{
    @Pointcut("execution(* com.nokia..ControllerExceptionHandler.*ValidatorHandler(..))")
    public void validatorExceptionHandlerPointcut()
    {
        // Pointcut
    }

    @Pointcut("execution(public * com.nokia..*Controller.*(..))")
    public void controllerPointcut()
    {
        // Pointcut
    }

    @Pointcut("execution(* com.nokia..ControllerExceptionHandler.*(..))")
    public void controllerExceptionHandlerPointcut()
    {
        // Pointcut
    }

    @Pointcut("controllerPointcut() || validatorExceptionHandlerPointcut()")
    public void beforePointCut()
    {
        // Pointcut
    }

    @Pointcut("controllerPointcut() || controllerExceptionHandlerPointcut()")
    public void afterPointCut()
    {
        // Pointcut
    }

    @Before("beforePointCut()")
    public void doBefore(JoinPoint joinPoint)
    {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null)
        {
            return;
        }
        HttpServletRequest request = attributes.getRequest();
        // 打印请求信息
        log.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
        // 打印请求参数
        Object[] args = joinPoint.getArgs();
        List<Object> list = new ArrayList<>();
        for (Object arg : args) {
            if (arg instanceof ServletRequest
                    || arg instanceof ServletResponse
                    || arg instanceof MultipartFile
                    || arg instanceof Exception
            ) {
                continue;
            }
            list.add(arg);
        }
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        log.info("请求参数: {}", JSON.toJSONString(list));
    }

    @Around("afterPointCut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        MDC.put("traceId", UUID.randomUUID().toString().replace("-", ""));
        Object result = proceedingJoinPoint.proceed();
        stopWatch.stop();
        log.info("返回: {}", JSON.toJSONString(result));
        log.info("耗时：{} ms", stopWatch.getTotalTimeMillis());
        return result;
    }
}