package com.gameplatform.server.aspect;

import com.gameplatform.server.annotation.RepeatCall;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * 重复调用切面
 * 处理被 @RepeatCall 注解标记的方法，实现重复执行逻辑
 * 目前主要支持返回 Mono 类型的方法
 */
@Aspect
@Component
public class RepeatCallAspect {
    
    private static final Logger log = LoggerFactory.getLogger(RepeatCallAspect.class);
    
    @Around("@annotation(repeatCall)")
    public Object repeatCall(ProceedingJoinPoint joinPoint, RepeatCall repeatCall) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        int times = repeatCall.times();
        String description = repeatCall.description().isEmpty() ? methodName : repeatCall.description();
        
        log.info("开始重复调用: {}.{} - {} (将执行{}次)", className, methodName, description, times);
        
        // 执行第一次调用
        Mono<Object> currentCall = executeOnce(joinPoint, className, methodName, description, 1);
        
        // 链式执行后续调用
        for (int i = 2; i <= times; i++) {
            final int attemptNumber = i;
            currentCall = currentCall
                    .onErrorReturn("第" + (attemptNumber - 1) + "次调用失败")
                    .flatMap(result -> {
                        log.debug("第{}次调用完成，准备执行第{}次", attemptNumber - 1, attemptNumber);
                        return executeOnce(joinPoint, className, methodName, description, attemptNumber);
                    });
        }
        
        return currentCall
                .onErrorReturn("最后一次调用失败")
                .doOnSuccess(finalResult -> {
                    log.info("重复调用全部完成: {}.{} - {} (执行了{}次), 最终结果={}", 
                            className, methodName, description, times, finalResult);
                });
    }
    
    /**
     * 执行单次调用
     */
    private Mono<Object> executeOnce(ProceedingJoinPoint joinPoint, String className, 
                                    String methodName, String description, int attemptNumber) {
        return Mono.defer(() -> {
            try {
                Object result = joinPoint.proceed();
                if (result instanceof Mono) {
                    return ((Mono<?>) result).cast(Object.class);
                } else {
                    return Mono.just(result);
                }
            } catch (Throwable throwable) {
                return Mono.error(throwable);
            }
        })
        .doOnSuccess(result -> {
            log.debug("重复调用第{}次成功: {}.{} - {}, 结果={}", 
                    attemptNumber, className, methodName, description, result);
        })
        .doOnError(error -> {
            log.warn("重复调用第{}次失败: {}.{} - {}, 错误={}", 
                    attemptNumber, className, methodName, description, error.toString());
        });
    }
}