package kr.co.accura.wbx.spring.datasource;

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.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @DataSource 어노테이션 AOP
 * <p>
 * wbx.spring.datasource.routing-enabled=true 일 때 활성화.
 * 메서드 → 클래스 순서로 @DataSource 어노테이션을 탐색합니다.
 */
@Slf4j
@Aspect
@Component
@Order(-1) // 트랜잭션 AOP보다 먼저 실행
@ConditionalOnProperty(name = "wbx.spring.datasource.routing-enabled", havingValue = "true")
public class DataSourceAspect {

    @Around("@annotation(kr.co.accura.wbx.spring.datasource.DataSource) || " +
            "@within(kr.co.accura.wbx.spring.datasource.DataSource)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        // 메서드 레벨 우선
        DataSource ds = method.getAnnotation(DataSource.class);
        if (ds == null) {
            // 클래스 레벨
            ds = point.getTarget().getClass().getAnnotation(DataSource.class);
        }

        String key = (ds != null) ? ds.value() : "app";
        String previous = WbxRoutingDataSource.getDataSourceKey();

        try {
            WbxRoutingDataSource.setDataSourceKey(key);
            log.debug("DataSource switched to: {}", key);
            return point.proceed();
        } finally {
            if (previous != null) {
                WbxRoutingDataSource.setDataSourceKey(previous);
            } else {
                WbxRoutingDataSource.clear();
            }
        }
    }
}
