package com.sckw.log.TraceLog.aop;

import com.alibaba.fastjson.JSON;
import com.sckw.core.model.constant.StringConstant;
import com.sckw.core.utils.UUIDUtils;
import com.sckw.log.TraceLog.TraceLog;
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.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
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;

/**
 * @author lfdc
 * @description
 * @date 2023-11-21 15:11:54
 */
@Slf4j
@Aspect
@Component
public class TraceIdAspect {

    private static final String TIME_PATTERN = "yyyy-MM-dd HH:mm:ss:SSS";

    @Value("${spring.application.name}")
    private String shortName;

    //    @Pointcut("@annotation(com.sckw.slope.detection.common.config.log.TraceId)")
    @Pointcut("@annotation(l)")
    public void traceId(TraceLog l) {
    }

    @Around("traceId(l)")
    public Object arround(ProceedingJoinPoint joinPoint, TraceLog l)  throws Throwable{
        MDC.put(StringConstant.TRACE_ID, UUIDUtils.get32UUID() + StringConstant.RUNG + l.description() /*+ shortName*/);
//        try {
//            long start = System.currentTimeMillis();
//            Object o = joinPoint.proceed();
//            long end = System.currentTimeMillis();
//            log.info("方法耗时：{} ms", end - start);
//            return o;
//        } catch (Throwable e) {
//            return e.getMessage();
//        } finally {
//            MDC.clear();
//        }
        Object result = null;
        //开始时间
        Date startTime = new Date();
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.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 {
            log.info("请求参数 param：{} ",param);
            long start = System.currentTimeMillis();
            //执行结果，返回参数
            result = joinPoint.proceed();
            long end = System.currentTimeMillis();
            log.info("响应结果 result：{} ",JSON.toJSONString(result));
            log.info("方法耗时：{} ms", end - start);
        } 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);
                        log.info("{}:{}.{}," +
                            "exception={}," +
                            "[{}->{}],slowRequest{}=[{}]", l.description(), targetName, methodName,
                    exception,
                    DateFormatUtils.format(startTime, TIME_PATTERN),
                    DateFormatUtils.format(endTime, TIME_PATTERN),
                    slowRequest,
                    time);
            MDC.clear();
        }
        return result;
    }
}