package com.unicorn.hgzero.common.aop;

import lombok.extern.slf4j.Slf4j;
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 java.util.Arrays;

/**
 * 로깅 AOP
 * Controller, Service 메서드 실행 시 로그를 자동으로 기록
 */
@Slf4j
@Aspect
@Component
public class LoggingAspect {

    /**
     * Controller 메서드 포인트컷
     */
    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void controllerPointcut() {
        // Pointcut for all methods in @RestController classes
    }

    /**
     * Service 메서드 포인트컷
     */
    @Pointcut("within(@org.springframework.stereotype.Service *)")
    public void servicePointcut() {
        // Pointcut for all methods in @Service classes
    }

    /**
     * Controller 메서드 실행 로깅
     *
     * @param joinPoint 조인 포인트
     * @return 메서드 실행 결과
     * @throws Throwable 예외 발생 시
     */
    @Around("controllerPointcut()")
    public Object logController(ProceedingJoinPoint joinPoint) throws Throwable {
        String className = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();

        log.info("[Controller] {}.{} 호출 - 파라미터: {}",
                className, methodName, Arrays.toString(args));

        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = joinPoint.proceed();
            long executionTime = System.currentTimeMillis() - startTime;
            log.info("[Controller] {}.{} 완료 - 실행시간: {}ms",
                    className, methodName, executionTime);
            return result;
        } catch (Exception e) {
            long executionTime = System.currentTimeMillis() - startTime;
            log.error("[Controller] {}.{} 실패 - 실행시간: {}ms, 에러: {}",
                    className, methodName, executionTime, e.getMessage());
            throw e;
        }
    }

    /**
     * Service 메서드 실행 로깅
     *
     * @param joinPoint 조인 포인트
     * @return 메서드 실행 결과
     * @throws Throwable 예외 발생 시
     */
    @Around("servicePointcut()")
    public Object logService(ProceedingJoinPoint joinPoint) throws Throwable {
        String className = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();

        log.debug("[Service] {}.{} 시작", className, methodName);

        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = joinPoint.proceed();
            long executionTime = System.currentTimeMillis() - startTime;
            log.debug("[Service] {}.{} 완료 - 실행시간: {}ms",
                    className, methodName, executionTime);
            return result;
        } catch (Exception e) {
            long executionTime = System.currentTimeMillis() - startTime;
            log.error("[Service] {}.{} 실패 - 실행시간: {}ms, 에러: {}",
                    className, methodName, executionTime, e.getMessage());
            throw e;
        }
    }
}
