package com.example.scaffold.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.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 性能监控切面 - 统计方法执行时间
 */
@Slf4j
@Aspect
@Component
public class PerformanceAspect {
    
    private final Map<String, MethodStats> statsMap = new ConcurrentHashMap<>();
    
    public static class MethodStats {
        public final AtomicLong totalCount = new AtomicLong();
        public final AtomicLong totalTime = new AtomicLong();
        public final AtomicLong maxTime = new AtomicLong();
        public final AtomicLong errorCount = new AtomicLong();
    }
    
    @Around("execution(* com.example.scaffold..*.*(..)) && !within(com.example.scaffold.security..*) && !within(org.springframework.web.filter..*)")
    public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        String key = joinPoint.getTarget().getClass().getSimpleName() + "." + joinPoint.getSignature().getName();
        long startTime = System.nanoTime();
        
        try {
            Object result = joinPoint.proceed();
            recordSuccess(key, System.nanoTime() - startTime);
            return result;
        } catch (Throwable ex) {
            recordError(key, System.nanoTime() - startTime);
            throw ex;
        }
    }
    
    private void recordSuccess(String key, long durationNanos) {
        MethodStats stats = statsMap.computeIfAbsent(key, k -> new MethodStats());
        stats.totalCount.incrementAndGet();
        stats.totalTime.addAndGet(durationNanos);
        long durationMs = durationNanos / 1_000_000;
        stats.maxTime.updateAndGet(current -> Math.max(current, durationMs));
    }
    
    private void recordError(String key, long durationNanos) {
        MethodStats stats = statsMap.computeIfAbsent(key, k -> new MethodStats());
        stats.totalCount.incrementAndGet();
        stats.errorCount.incrementAndGet();
        stats.totalTime.addAndGet(durationNanos);
    }
    
    public Map<String, MethodStats> getStats() {
        return new ConcurrentHashMap<>(statsMap);
    }
    
    public void resetStats() {
        statsMap.clear();
    }
}