content: package com.alphabugx.util;
  
  import java.io.PrintStream;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.atomic.AtomicInteger;
  import java.util.concurrent.atomic.AtomicLong;
  
  /**
   * 详细进度报告器
   * 支持实时进度显示、详细模式切换、多线程安全
   */
  public class ProgressReporter {
      
      private static final ProgressReporter INSTANCE = new ProgressReporter();
      
      // 显示模式
      public enum DisplayMode {
          SIMPLE,   // 简洁模式：只显示主要进度
          DETAILED  // 详细模式：显示所有操作细节
      }
      
      // 进度数据
      private volatile DisplayMode currentMode = DisplayMode.SIMPLE;
      private volatile String currentMainTask = "";
      private volatile String currentSubTask = "";
      private volatile int mainProgress = 0;
      private volatile int subProgress = 0;
      private volatile int totalFiles = 0;
      private volatile int processedFiles = 0;
      
      // 统计信息
      private final AtomicLong startTime = new AtomicLong(0);
      private final AtomicInteger successCount = new AtomicInteger(0);
      private final AtomicInteger failureCount = new AtomicInteger(0);
      private final ConcurrentHashMap<String, Long> stepTimings = new ConcurrentHashMap<>();
      
      // 输出流
      private PrintStream out = System.out;
      private PrintStream err = System.err;
      
      // 格式化器
      private final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
      
      private ProgressReporter() {}
      
      public static ProgressReporter getInstance() {
          return INSTANCE;
      }
      
      /**
       * 切换显示模式
       */
      public void toggleMode() {
          currentMode = (currentMode == DisplayMode.SIMPLE) ? DisplayMode.DETAILED : DisplayMode.SIMPLE;
          out.println("\n" + getTimestamp() + " [模式] 切换到" + 
                     (currentMode == DisplayMode.DETAILED ? "详细模式" : "简洁模式"));
          refreshDisplay();
      }
      
      /**
       * 设置显示模式
       */
      public void setDisplayMode(DisplayMode mode) {
          this.currentMode = mode;
          out.println("\n" + getTimestamp() + " [模式] 设置为" + 
                     (mode == DisplayMode.DETAILED ? "详细模式" : "简洁模式"));
      }
      
      /**
       * 开始新的主任务
       */
      public void startMainTask(String taskName, int totalSteps) {
          this.currentMainTask = taskName;
          this.mainProgress = 0;
          this.totalFiles = totalSteps;
          this.processedFiles = 0;
          this.startTime.set(System.currentTimeMillis());
          this.successCount.set(0);
          this.failureCount.set(0);
          this.stepTimings.clear();
          
          out.println("\n" + repeatString("=", 60));
          out.println(getTimestamp() + " [开始] " + taskName);
          out.println(repeatString("=", 60));
          
          if (currentMode == DisplayMode.DETAILED) {
              out.println("总步骤: " + totalSteps);
              out.println("显示模式: 详细 (输入 'toggle' 切换到简洁模式)");
          }
          
          refreshDisplay();
      }
      
      /**
       * 更新主任务进度
       */
      public void updateMainProgress(int progress, String description) {
          this.mainProgress = progress;
          this.currentSubTask = description;
          
          if (currentMode == DisplayMode.DETAILED) {
              out.println(getTimestamp() + " [主进度] " + progress + "% - " + description);
          }
          
          refreshDisplay();
      }
      
      /**
       * 开始子任务
       */
      public void startSubTask(String subTaskName) {
          this.currentSubTask = subTaskName;
          this.subProgress = 0;
          
          if (currentMode == DisplayMode.DETAILED) {
              out.println(getTimestamp() + " [子任务] " + subTaskName);
          }
          
          stepTimings.put(subTaskName, System.currentTimeMillis());
          refreshDisplay();
      }
      
      /**
       * 更新子任务进度
       */
      public void updateSubProgress(int progress, String detail) {
          this.subProgress = progress;
          
          if (currentMode == DisplayMode.DETAILED) {
              out.println(getTimestamp() + " [子进度] " + progress + "% - " + detail);
          }
          
          refreshDisplay();
      }
      
      /**
       * 完成子任务
       */
      public void completeSubTask(boolean success) {
          if (success) {
              successCount.incrementAndGet();
          } else {
              failureCount.incrementAndGet();
          }
          
          this.processedFiles++;
          
          // 记录耗时
          Long startTime = stepTimings.get(currentSubTask);
          if (startTime != null) {
              long duration = System.currentTimeMillis() - startTime;
              if (currentMode == DisplayMode.DETAILED) {
                  out.println(getTimestamp() + " [完成] " + currentSubTask + 
                             " (" + (success ? "成功" : "失败") + ", 耗时: " + formatDuration(duration) + ")");
              }
          }
          
          this.subProgress = 100;
          refreshDisplay();
      }
      
      /**
       * 报告文件处理进度
       */
      public void reportFileProgress(String fileName, int fileIndex, int totalFiles, String operation) {
          this.processedFiles = fileIndex;
          this.totalFiles = totalFiles;
          this.currentSubTask = operation + ": " + fileName;
          
          int progress = (int) ((fileIndex * 100.0) / totalFiles);
          
          if (currentMode == DisplayMode.DETAILED) {
              out.println(getTimestamp() + " [文件] [" + fileIndex + "/" + totalFiles + "] " + 
                         operation + ": " + fileName);
          }
          
          refreshDisplay();
      }
      
      /**
       * 报告错误
       */
      public void reportError(String errorMessage, Exception exception) {
          String errorLog = getTimestamp() + " [错误] " + errorMessage;
          com.alphabugx.util.EncodingHelper.safeErrorPrintln(errorLog);
          
          if (currentMode == DisplayMode.DETAILED && exception != null) {
              String detailError = "详细错误: " + exception.getMessage();
              com.alphabugx.util.EncodingHelper.safeErrorPrintln(detailError);
              
              if (exception.getCause() != null) {
                  String causeError = "根本原因: " + exception.getCause().getMessage();
                  com.alphabugx.util.EncodingHelper.safeErrorPrintln(causeError);
              }
          }
          failureCount.incrementAndGet();
      }
      
      /**
       * 报告警告
       */
      public void reportWarning(String warningMessage) {
          if (currentMode == DisplayMode.DETAILED) {
              out.println(getTimestamp() + " [警告] " + warningMessage);
          }
      }
      
      /**
       * 报告信息
       */
      public void reportInfo(String infoMessage) {
          if (currentMode == DisplayMode.DETAILED) {
              out.println(getTimestamp() + " [信息] " + infoMessage);
          }
      }
      
      /**
       * 完成主任务
       */
      public void completeMainTask() {
          long totalDuration = System.currentTimeMillis() - startTime.get();
          
          out.println("\n" + repeatString("=", 60));
          out.println(getTimestamp() + " [完成] " + currentMainTask);
          out.println("总耗时: " + formatDuration(totalDuration));
          out.println("成功: " + successCount.get() + ", 失败: " + failureCount.get());
          out.println(repeatString("=", 60) + "\n");
      }
      
      /**
       * 刷新显示（在控制台同一行更新简洁进度）
       */
      private void refreshDisplay() {
          if (currentMode == DisplayMode.SIMPLE) {
              // 简洁模式：在同一行显示进度
              StringBuilder sb = new StringBuilder();
              sb.append("\r"); // 回到行首
              
              // 主进度条
              sb.append("[");
              int barLength = 30;
              int filledLength = (mainProgress * barLength) / 100;
              for (int i = 0; i < barLength; i++) {
                  if (i < filledLength) {
                      sb.append("█");
                  } else {
                      sb.append("░");
                  }
              }
              sb.append("] ");
              
              // 进度百分比
              sb.append(String.format("%3d%%", mainProgress));
              
              // 文件进度
              if (totalFiles > 0) {
                  sb.append(String.format(" [%d/%d]", processedFiles, totalFiles));
              }
              
              // 当前任务
              if (!currentSubTask.isEmpty()) {
                  String shortTask = currentSubTask.length() > 40 ? 
                      currentSubTask.substring(0, 37) + "..." : currentSubTask;
                  sb.append(" " + shortTask);
              }
              
              // 清除行尾
              sb.append("                    ");
              
              out.print(sb.toString());
              out.flush();
          }
      }
      
      /**
       * 获取时间戳
       */
      private String getTimestamp() {
          return timeFormat.format(new Date());
      }
      
      /**
       * 格式化持续时间
       */
      private String formatDuration(long milliseconds) {
          if (milliseconds < 1000) {
              return milliseconds + "ms";
          } else if (milliseconds < 60000) {
              return String.format("%.1fs", milliseconds / 1000.0);
          } else {
              long minutes = milliseconds / 60000;
              long seconds = (milliseconds % 60000) / 1000;
              return String.format("%dm%ds", minutes, seconds);
          }
      }
      
      /**
       * 获取当前统计信息
       */
      public String getStatistics() {
          long elapsed = System.currentTimeMillis() - startTime.get();
          return String.format("统计 - 成功: %d, 失败: %d, 耗时: %s", 
                             successCount.get(), failureCount.get(), formatDuration(elapsed));
      }
      
      /**
       * 获取当前显示模式
       */
      public DisplayMode getCurrentMode() {
          return currentMode;
      }
      
      /**
       * 重复字符串（Java 8兼容版本）
       */
      private String repeatString(String str, int count) {
          StringBuilder sb = new StringBuilder();
          for (int i = 0; i < count; i++) {
              sb.append(str);
          }
          return sb.toString();
      }
  } 