package com.example.demo.aop;

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.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 性能监控切面 - 演示 @Around 环绕通知
 * 
 * 学习点：
 * - @Around 最强大的通知类型
 * - ProceedingJoinPoint 控制方法执行
 * - 方法执行时间统计
 */
@Aspect
@Component
public class PerformanceAspect {
    
    // 方法执行时间统计
    private final Map<String, Long> totalTimes = new ConcurrentHashMap<>();
    private final Map<String, Long> callCounts = new ConcurrentHashMap<>();
    
    /**
     * 环绕通知 - 统计方法执行时间
     */
    @Around("execution(* com.example.demo.controller.*.*(..)) || " +
            "execution(* com.example.demo.service.*.*(..))")
    public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().toShortString();
        
        long startTime = System.currentTimeMillis();
        
        try {
            // 执行目标方法
            Object result = joinPoint.proceed();
            
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            
            // 记录统计
            totalTimes.merge(methodName, duration, Long::sum);
            callCounts.merge(methodName, 1L, Long::sum);
            
            System.out.println("[AOP-Performance] " + methodName + 
                " 执行耗时: " + duration + "ms");
            
            return result;
        } catch (Throwable e) {
            long endTime = System.currentTimeMillis();
            System.out.println("[AOP-Performance] " + methodName + 
                " 异常耗时: " + (endTime - startTime) + "ms");
            throw e;
        }
    }
    
    /**
     * 获取性能统计
     */
    public Map<String, Map<String, Long>> getStatistics() {
        Map<String, Map<String, Long>> stats = new HashMap<>();
        
        for (String method : totalTimes.keySet()) {
            Map<String, Long> methodStats = new HashMap<>();
            methodStats.put("totalTime", totalTimes.get(method));
            methodStats.put("callCount", callCounts.get(method));
            methodStats.put("avgTime", totalTimes.get(method) / callCounts.get(method));
            stats.put(method, methodStats);
        }
        
        return stats;
    }
}