package com.ga.common.aop;

import com.ga.common.system.ApiAccessLogService;
import com.ga.common.util.SecurityUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 모든 @RestController 의 요청을 비동기 로깅한다.
 * - URL, Method, 응답시간, 사용자
 * - 민감 파라미터(비밀번호 등)는 마스킹
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class ApiLogAspect {

    private final ApiAccessLogService apiAccessLogService;

    @Around("within(@org.springframework.web.bind.annotation.RestController *)")
    public Object log(ProceedingJoinPoint jp) throws Throwable {
        long start = System.currentTimeMillis();
        Throwable error = null;
        Object result = null;
        try {
            result = jp.proceed();
            return result;
        } catch (Throwable e) {
            error = e;
            throw e;
        } finally {
            try {
                int elapsed = (int) (System.currentTimeMillis() - start);
                HttpServletRequest req = currentRequest();
                if (req != null) {
                    apiAccessLogService.saveAsync(
                            SecurityUtil.getCurrentUserId(),
                            req.getMethod(),
                            req.getRequestURI(),
                            queryString(req),
                            error == null ? "200" : "500",
                            elapsed,
                            ipOf(req),
                            error == null ? null : error.getMessage()
                    );
                }
            } catch (Exception ex) {
                log.debug("ApiLog save failed: {}", ex.getMessage());
            }
        }
    }

    private HttpServletRequest currentRequest() {
        var attr = RequestContextHolder.getRequestAttributes();
        return attr instanceof ServletRequestAttributes sra ? sra.getRequest() : null;
    }

    private String queryString(HttpServletRequest req) {
        String qs = req.getQueryString();
        if (qs == null) return null;
        // 민감 파라미터 마스킹
        return qs.replaceAll("(password|pwd|token)=[^&]*", "$1=***");
    }

    private String ipOf(HttpServletRequest req) {
        String xf = req.getHeader("X-Forwarded-For");
        if (xf != null && !xf.isBlank()) return xf.split(",")[0].trim();
        return req.getRemoteAddr();
    }
}
