package com.sckw.core.aspect;

import com.alibaba.fastjson.JSON;
import com.sckw.core.annotation.Log;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
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.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @desc: controller请求切面增强
 * @author: yzc
 * @date: 2023-08-02 9:21
 */
@Aspect
@Component
@Slf4j
public class LogAspect {
    private static final String TIME_PATTERN = "yyyy-MM-dd HH:mm:ss:SSS";

    @Pointcut("@annotation(l)")
    public void loggerPointcut(Log l) {
    }

    @Around(value = "loggerPointcut(l)", argNames = "p,l")
    public Object around(ProceedingJoinPoint p, Log l) throws Throwable {
        Object result = null;
        //开始时间
        Date startTime = new Date();
        String targetName = p.getTarget().getClass().getName();
        String methodName = p.getSignature().getName();
        Object[] args = p.getArgs();
        Stream<?> stream = ArrayUtils.isEmpty(args) ? Stream.empty() : Arrays.stream(args);
        List<Object> logArgs = stream
                .filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse)) && !(arg instanceof MultipartFile))
                .collect(Collectors.toList());
        //过滤后序列化无异常
        String param = JSON.toJSONString(logArgs);
        String exception = "";
        try {
            //执行结果，返回参数
            result = p.proceed();
        } catch (Throwable e) {
            exception = e.getMessage();
            //异常抛出
            throw e;
        } finally {
            Date endTime = new Date();
            long time = endTime.getTime() - startTime.getTime();
            Boolean slowRequest = (time > 1500L);
            log.info("{}:{}.{}," +
                            "param={}," +
                            "result={}," +
                            "exception={}," +
                            "[{}->{}],slowRequest{}=[{}]", l.description(), targetName, methodName,
                    param,
                    JSON.toJSONString(result),
                    exception,
                    DateFormatUtils.format(startTime, TIME_PATTERN),
                    DateFormatUtils.format(endTime, TIME_PATTERN),
                    slowRequest,
                    time);
        }
        return result;
    }

}
