package com.caliverse.admin.global.common.aspect;

import com.caliverse.admin.global.common.annotation.RequestLog;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Map;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class RequestLogAspect {

    private final ObjectMapper objectMapper;

    @Before("@annotation(requestLog)")
    public void logAnnotatedRequest(JoinPoint joinPoint, RequestLog requestLog) {
        try {
            String email = CommonUtils.getAdmin() != null ? CommonUtils.getAdmin().getEmail() : "";
            String methodName = joinPoint.getSignature().getName();
            String className = joinPoint.getTarget().getClass().getSimpleName();

            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Parameter[] parameters = signature.getMethod().getParameters();
            Object[] args = joinPoint.getArgs();

            StringBuilder logMessage = new StringBuilder();
            logMessage.append(String.format("%s.%s user: %s", className, methodName, email));

            // 어노테이션 설정에 따른 파라미터 필터링
            for (int i = 0; i < parameters.length && i < args.length; i++) {
                if (args[i] != null) {
                    String paramName = parameters[i].getName();

                    // 제외할 파라미터 체크
                    if (requestLog.excludeParams().length > 0 &&
                            Arrays.asList(requestLog.excludeParams()).contains(paramName)) {
                        continue;
                    }

                    // 포함할 파라미터 체크 (설정된 경우)
                    if (requestLog.includeParams().length > 0 &&
                            !Arrays.asList(requestLog.includeParams()).contains(paramName)) {
                        continue;
                    }

                    Object paramValue = args[i];

                    if (paramValue instanceof Map) {
                        try {
                            String jsonValue = objectMapper.writeValueAsString(paramValue);
                            logMessage.append(String.format(", %s: %s", paramName, jsonValue));
                        } catch (Exception e) {
                            logMessage.append(String.format(", %s: %s", paramName, paramValue.toString()));
                        }
                    } else {
                        logMessage.append(String.format(", %s: %s", paramName, paramValue.toString()));
                    }
                }
            }

            // 로그 레벨에 따른 출력
            switch (requestLog.level().toUpperCase()) {
                case "DEBUG":
                    log.debug(logMessage.toString());
                    break;
                case "WARN":
                    log.warn(logMessage.toString());
                    break;
                case "ERROR":
                    log.error(logMessage.toString());
                    break;
                default:
                    log.info(logMessage.toString());
                    break;
            }

        } catch (Exception e) {
            log.warn("로깅 중 오류 발생: {}", e.getMessage());
        }
    }
}
