const BAR_WIDTH = 30;

function formatDuration(ms: number): string {
  if (!Number.isFinite(ms) || ms < 0) return "?";
  const totalSeconds = Math.ceil(ms / 1000);
  if (totalSeconds < 60) return `${totalSeconds}s`;
  const minutes = Math.floor(totalSeconds / 60);
  const seconds = totalSeconds % 60;
  if (minutes < 60) return `${minutes}m ${seconds}s`;
  const hours = Math.floor(minutes / 60);
  const remMinutes = minutes % 60;
  return `${hours}h ${remMinutes}m`;
}

function renderBar(percent: number): string {
  const clamped = Math.max(0, Math.min(100, percent));
  const filled = Math.round((clamped / 100) * BAR_WIDTH);
  const empty = BAR_WIDTH - filled;
  return `[${"█".repeat(filled)}${"░".repeat(empty)}]`;
}

export class ProgressReporter {
  private readonly startTime = Date.now();
  private lastLineLength = 0;

  constructor(private readonly total: number) {}

  update(processed: number): void {
    const percent = this.total > 0 ? (processed / this.total) * 100 : 100;
    const elapsed = Date.now() - this.startTime;
    const avgMs = processed > 0 ? elapsed / processed : 0;
    const remaining = this.total - processed;
    const etaMs = processed > 0 ? remaining * avgMs : 0;

    const line = [
      renderBar(percent),
      `${percent.toFixed(1)}%`,
      `(${processed}/${this.total})`,
      processed > 0 && remaining > 0 ? `~${formatDuration(etaMs)} restantes` : "",
    ]
      .filter(Boolean)
      .join(" ");

    const padded =
      line.length < this.lastLineLength
        ? line + " ".repeat(this.lastLineLength - line.length)
        : line;
    this.lastLineLength = padded.length;

    process.stdout.write(`\r${padded}`);
  }

  finish(): void {
    process.stdout.write("\n");
  }
}
