package com.lesingle.creation.common.aspect;

import com.lesingle.creation.common.util.TraceIdUtil;
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.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * 日志切面
 * <p>
 * 拦截 Controller 层所有方法，记录请求日志
 * 包含：TraceId、请求方法、请求路径、IP、耗时
 *
 * @author lesingle
 * @since 1.0.0
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    /**
     * 定义切点：拦截 Controller 层所有方法
     */
    @Pointcut("execution(* com.lesingle.creation.controller..*.*(..))")
    public void controllerPointcut() {
    }

    /**
     * 环绕通知：记录请求耗时
     */
    @Around("controllerPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes =
            (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return joinPoint.proceed();
        }

        HttpServletRequest request = attributes.getRequest();
        String traceId = TraceIdUtil.getTraceId();
        String method = request.getMethod();
        String uri = request.getRequestURI();
        String ip = getIpAddress(request);

        long startTime = System.currentTimeMillis();
        log.info("【{}】请求开始 | 方法：{} | 路径：{} | IP：{}", traceId, method, uri, ip);

        Object result;
        try {
            result = joinPoint.proceed();
            long endTime = System.currentTimeMillis();
            log.info("【{}】请求成功 | 方法：{} | 路径：{} | 耗时：{}ms",
                traceId, method, uri, (endTime - startTime));
        } catch (Throwable e) {
            long endTime = System.currentTimeMillis();
            log.error("【{}】请求异常 | 方法：{} | 路径：{} | 耗时：{}ms | 异常：{}",
                traceId, method, uri, (endTime - startTime), e.getMessage(), e);
            throw e;
        }

        return result;
    }

    /**
     * 获取请求 IP 地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            // 如果是本地 IPv6，转换为 IPv4
            if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
                try {
                    ip = InetAddress.getLocalHost().getHostAddress();
                } catch (UnknownHostException e) {
                    log.error("获取 IP 地址失败：{}", e.getMessage());
                }
            }
        }
        // 多个代理时，取第一个 IP
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }

}
