content: package com.example.demo.config;
  
  import com.example.demo.service.ToolExecutionLogger;
  import com.example.demo.service.LogStreamService;
  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.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Component;
  
  
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  /**
   * 工具调用日志切面
   * 拦截 Spring AI 的工具调用并提供中文日志
   */
  @Aspect
  @Component
  public class ToolCallLoggingAspect {
      
      private static final Logger logger = LoggerFactory.getLogger(ToolCallLoggingAspect.class);
      
      @Autowired
      private ToolExecutionLogger executionLogger;
  
      @Autowired
      private LogStreamService logStreamService;
      
      /**
       * 拦截使用@Tool注解的方法执行
       */
      @Around("@annotation(org.springframework.ai.tool.annotation.Tool)")
      public Object interceptToolAnnotation(ProceedingJoinPoint joinPoint) throws Throwable {
          Object[] args = joinPoint.getArgs();
          String methodName = joinPoint.getSignature().getName();
          String className = joinPoint.getSignature().getDeclaringType().getSimpleName();
  
          // 详细的参数信息
          String parametersInfo = formatMethodParameters(args);
          String fileInfo = extractFileInfoFromMethodArgs(methodName, args);
  
          logger.debug("🚀 [Spring AI @Tool] 执行工具: {}.{} | 参数: {} | 文件/目录: {}",
              className, methodName, parametersInfo, fileInfo);
  
          // 获取当前任务ID (从线程本地变量或其他方式)
          String taskId = getCurrentTaskId();
  
          // 推送工具开始执行事件
          if (taskId != null) {
              String startMessage = generateStartMessage(methodName, fileInfo);
              logStreamService.pushToolStart(taskId, methodName, fileInfo, startMessage);
          }
  
          long startTime = System.currentTimeMillis();
          try {
              Object result = joinPoint.proceed();
              long executionTime = System.currentTimeMillis() - startTime;
  
              logger.debug("✅ [Spring AI @Tool] 工具执行成功: {}.{} | 耗时: {}ms | 文件/目录: {} | 参数: {}",
                  className, methodName, executionTime, fileInfo, parametersInfo);
  
              // 推送工具执行成功事件
              if (taskId != null) {
                  String successMessage = generateSuccessMessage(methodName, fileInfo, result, executionTime);
                  logStreamService.pushToolSuccess(taskId, methodName, fileInfo, successMessage, executionTime);
              }
  
              return result;
          } catch (Throwable e) {
              long executionTime = System.currentTimeMillis() - startTime;
  
              logger.error("❌ [Spring AI @Tool] 工具执行失败: {}.{} | 耗时: {}ms | 文件/目录: {} | 参数: {} | 错误: {}",
                  className, methodName, executionTime, fileInfo, parametersInfo, e.getMessage());
  
              // 推送工具执行失败事件
              if (taskId != null) {
                  String errorMessage = generateErrorMessage(methodName, fileInfo, e.getMessage());
                  logStreamService.pushToolError(taskId, methodName, fileInfo, errorMessage, executionTime);
              }
  
              throw e;
          }
      }
  
      /**
       * 格式化方法参数为可读字符串
       */
      private String formatMethodParameters(Object[] args) {
          if (args == null || args.length == 0) {
              return "无参数";
          }
  
          StringBuilder sb = new StringBuilder();
          for (int i = 0; i < args.length; i++) {
              if (i > 0) sb.append(", ");
              Object arg = args[i];
              if (arg == null) {
                  sb.append("null");
              } else if (arg instanceof String) {
                  String str = (String) arg;
                  // 如果字符串太长，截断显示
                  if (str.length() > 100) {
                      sb.append("\"").append(str.substring(0, 100)).append("...\"");
                  } else {
                      sb.append("\"").append(str).append("\"");
                  }
              } else {
                  sb.append(arg.toString());
              }
          }
          return sb.toString();
      }
  
      /**
       * 从方法参数中直接提取文件信息
       */
      private String extractFileInfoFromMethodArgs(String methodName, Object[] args) {
          if (args == null || args.length == 0) {
              return "无参数";
          }
  
          try {
              switch (methodName) {
                  case "readFile":
                      // readFile(String absolutePath, Integer offset, Integer limit)
                      return args.length > 0 && args[0] != null ? args[0].toString() : "未指定路径";
  
                  case "writeFile":
                      // writeFile(String filePath, String content)
                      return args.length > 0 && args[0] != null ? args[0].toString() : "未指定路径";
  
                  case "editFile":
                      // editFile(String filePath, String oldText, String newText)
                      return args.length > 0 && args[0] != null ? args[0].toString() : "未指定路径";
  
                  case "listDirectory":
                      // listDirectory(String directoryPath, Boolean recursive)
                      return args.length > 0 && args[0] != null ? args[0].toString() : "未指定路径";
  
                  case "analyzeProject":
                      // analyzeProject(String projectPath, ...)
                      return args.length > 0 && args[0] != null ? args[0].toString() : "未指定路径";
  
                  case "scaffoldProject":
                      // scaffoldProject(String projectName, String projectType, String projectPath, ...)
                      return args.length > 2 && args[2] != null ? args[2].toString() : "未指定路径";
  
                  case "smartEdit":
                      // smartEdit(String projectPath, ...)
                      return args.length > 0 && args[0] != null ? args[0].toString() : "未指定路径";
  
                  default:
                      // 对于未知方法，尝试从第一个参数中提取路径
                      if (args.length > 0 && args[0] != null) {
                          String firstArg = args[0].toString();
                          if (firstArg.contains("/") || firstArg.contains("\\")) {
                              return firstArg;
                          }
                      }
                      return "未识别的工具类型";
              }
          } catch (Exception e) {
              return "解析参数失败: " + e.getMessage();
          }
      }
  
      /**
       * 从参数字符串中提取文件信息（备用方法）
       */
      private String extractFileInfoFromArgs(String toolName, String arguments) {
          try {
              switch (toolName) {
                  case "readFile":
                  case "read_file":
                      return extractPathFromString(arguments, "absolutePath", "filePath");
                  case "writeFile":
                  case "write_file":
                  case "editFile":
                  case "edit_file":
                      return extractPathFromString(arguments, "filePath");
                  case "listDirectory":
                      return extractPathFromString(arguments, "directoryPath", "path");
                  case "analyzeProject":
                  case "analyze_project":
                  case "scaffoldProject":
                  case "scaffold_project":
                  case "smartEdit":
                  case "smart_edit":
                      return extractPathFromString(arguments, "projectPath");
                  default:
                      return "未指定文件路径";
              }
          } catch (Exception e) {
              return "解析文件路径失败";
          }
      }
      
      /**
       * 从字符串中提取路径
       */
      private String extractPathFromString(String text, String... pathKeys) {
          for (String key : pathKeys) {
              // JSON 格式
              Pattern jsonPattern = Pattern.compile("\"" + key + "\"\\s*:\\s*\"([^\"]+)\"");
              Matcher jsonMatcher = jsonPattern.matcher(text);
              if (jsonMatcher.find()) {
                  return jsonMatcher.group(1);
              }
              
              // 键值对格式
              Pattern kvPattern = Pattern.compile(key + "=([^,\\s\\]]+)");
              Matcher kvMatcher = kvPattern.matcher(text);
              if (kvMatcher.find()) {
                  return kvMatcher.group(1);
              }
          }
  
          return "未找到路径";
      }
  
      /**
       * 获取当前任务ID
       * 从线程本地变量或请求上下文中获取
       */
      private String getCurrentTaskId() {
          // 这里需要从某个地方获取当前任务ID
          // 可以从ThreadLocal、RequestAttributes或其他方式获取
          try {
              // 临时实现：从线程名或其他方式获取
              return TaskContextHolder.getCurrentTaskId();
          } catch (Exception e) {
              logger.debug("无法获取当前任务ID: {}", e.getMessage());
              return null;
          }
      }
  
      /**
       * 生成工具开始执行消息
       */
      private String generateStartMessage(String toolName, String fileInfo) {
          switch (toolName) {
              case "readFile":
                  return "正在读取文件: " + getFileName(fileInfo);
              case "writeFile":
                  return "正在写入文件: " + getFileName(fileInfo);
              case "editFile":
                  return "正在编辑文件: " + getFileName(fileInfo);
              case "listDirectory":
                  return "正在列出目录: " + fileInfo;
              case "analyzeProject":
                  return "正在分析项目: " + fileInfo;
              case "scaffoldProject":
                  return "正在创建项目脚手架: " + fileInfo;
              case "smartEdit":
                  return "正在智能编辑项目: " + fileInfo;
              default:
                  return "正在执行工具: " + toolName;
          }
      }
  
      /**
       * 生成工具执行成功消息
       */
      private String generateSuccessMessage(String toolName, String fileInfo, Object result, long executionTime) {
          String fileName = getFileName(fileInfo);
          switch (toolName) {
              case "readFile":
                  return String.format("已读取文件 %s (耗时 %dms)", fileName, executionTime);
              case "writeFile":
                  return String.format("已写入文件 %s (耗时 %dms)", fileName, executionTime);
              case "editFile":
                  return String.format("已编辑文件 %s (耗时 %dms)", fileName, executionTime);
              case "listDirectory":
                  return String.format("已列出目录 %s (耗时 %dms)", fileInfo, executionTime);
              case "analyzeProject":
                  return String.format("已分析项目 %s (耗时 %dms)", fileInfo, executionTime);
              case "scaffoldProject":
                  return String.format("已创建项目脚手架 %s (耗时 %dms)", fileInfo, executionTime);
              case "smartEdit":
                  return String.format("已智能编辑项目 %s (耗时 %dms)", fileInfo, executionTime);
              default:
                  return String.format("工具 %s 执行成功 (耗时 %dms)", toolName, executionTime);
          }
      }
  
      /**
       * 生成工具执行失败消息
       */
      private String generateErrorMessage(String toolName, String fileInfo, String errorMsg) {
          String fileName = getFileName(fileInfo);
          return String.format("工具 %s 执行失败: %s (文件: %s)", toolName, errorMsg, fileName);
      }
  
      /**
       * 从文件路径中提取文件名
       */
      private String getFileName(String filePath) {
          if (filePath == null || filePath.isEmpty()) {
              return "未知文件";
          }
  
          // 处理Windows和Unix路径
          int lastSlash = Math.max(filePath.lastIndexOf('/'), filePath.lastIndexOf('\\'));
          if (lastSlash >= 0 && lastSlash < filePath.length() - 1) {
              return filePath.substring(lastSlash + 1);
          }
  
          return filePath;
      }
  }
  