package com.simuwang.deploy.components;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONUtil;
import com.simuwang.base.common.util.ServletUtils;
import com.simuwang.logging.Logging;
import com.simuwang.logging.LoggingService;
import com.simuwang.logging.SystemLog;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.annotation.Order;
import org.springframework.util.StopWatch;

import java.util.Objects;

/**
 * @author wangzaijun
 * @date 2024/9/14 14:07
 * @description 系统日志拦截切面
 */
@Order(2)
@Aspect
public class LoggingAspect {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final LoggingService service;

    public LoggingAspect(LoggingService service) {
        this.service = service;
    }

    @Around("@annotation(annotation)")
    public Object around(ProceedingJoinPoint joinPoint, SystemLog annotation) {
        Class<?> clazz = AopUtils.getTargetClass(joinPoint.getTarget());
        SystemLog systemLog = clazz.getAnnotation(SystemLog.class);
        String title = annotation.value();
        if (systemLog != null && StrUtil.isNotBlank(systemLog.value())) {
            title = systemLog.value() + "-" + title;
        }
        HttpServletRequest request = ServletUtils.getRequest();
        Logging.Builder builder = Logging.builder().title(title).type(annotation.type().getValue()).method(request.getMethod())
                .requestUri(URLUtil.getPath(request.getRequestURI())).remoteAddr(ServletUtils.getIpAddr(request))
                .params(joinPoint.getArgs() == null ? Objects.toString(request.getParameterMap()) : JSONUtil.toJsonStr(joinPoint.getArgs()));
        StopWatch watch = new StopWatch();
        watch.start();
        Object result = null;
        try {
            result = joinPoint.proceed();
            if (annotation.saveResult()) {
                builder.result(JSONUtil.toJsonStr(result));
            }
        } catch (Throwable throwable) {
            builder.exception(ExceptionUtil.stacktraceToString(throwable));
        } finally {
            watch.stop();
            builder.executeTime(watch.getTotalTimeMillis());
            Logging logging = builder.build();
            try {
                this.service.asyncSave(logging);
            } catch (Exception e) {
                this.logger.warn("请求{} 日志保存报错\n{}", logging, ExceptionUtil.stacktraceToString(e));
            }
        }
        return result;
    }
}
