"use strict";
/* Socket Lib - Built with esbuild */
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var progress_exports = {};
__export(progress_exports, {
  ProgressBar: () => ProgressBar,
  createProgressIndicator: () => createProgressIndicator
});
module.exports = __toCommonJS(progress_exports);
var import_node_process = __toESM(require("node:process"));
var import_yoctocolors_cjs = __toESM(require("../external/yoctocolors-cjs"));
var import_strip = require("../ansi/strip");
var import_format = require("../strings/format");
var import_date = require("../primordials/date");
var import_math = require("../primordials/math");
var import_object = require("../primordials/object");
var import_string = require("../primordials/string");
class ProgressBar {
  current = 0;
  total;
  startTime;
  lastRender = 0;
  stream;
  options;
  terminated = false;
  lastDrawnWidth = 0;
  /**
   * Create a new progress bar instance.
   *
   * @example
   *   ;```ts
   *   const bar = new ProgressBar(100, {
   *     width: 50,
   *     format: ':bar :percent :current/:total :eta',
   *     color: 'green',
   *   })
   *   ```
   *
   * @param total - Total number of units for the progress bar.
   * @param options - Configuration options for the progress bar.
   */
  constructor(total, options) {
    this.total = total;
    this.startTime = (0, import_date.DateNow)();
    this.stream = options?.stream || import_node_process.default.stderr;
    this.options = {
      width: 40,
      format: ":bar :percent :current/:total",
      complete: "\u2588",
      incomplete: "\u2591",
      head: "",
      clear: false,
      // ~60fps.
      renderThrottle: 16,
      stream: this.stream,
      color: "cyan",
      ...options
    };
  }
  /**
   * Update progress to a specific value and redraw the bar. Updates are
   * throttled to prevent excessive rendering (default ~60fps).
   *
   * @example
   *   ;```ts
   *   bar.update(50)
   *   bar.update(75, { status: 'Processing...' })
   *   ```
   *
   * @param current - Current progress value (will be clamped to total)
   * @param tokens - Optional custom tokens to replace in format string.
   */
  update(current, tokens) {
    if (this.terminated) {
      return;
    }
    this.current = (0, import_math.MathMin)(current, this.total);
    const now = (0, import_date.DateNow)();
    if (now - this.lastRender < (this.options.renderThrottle ?? 16) && this.current < this.total) {
      return;
    }
    this.lastRender = now;
    this.render(tokens);
    if (this.current >= this.total) {
      this.terminate();
    }
  }
  /**
   * Increment progress by a specified amount. Convenience method for
   * `update(current + amount)`.
   *
   * @example
   *   ;```ts
   *   bar.tick() // Increment by 1
   *   bar.tick(5) // Increment by 5
   *   bar.tick(1, { file: 'data.json' })
   *   ```
   *
   * @default amount 1
   *
   * @param amount - Amount to increment by.
   * @param tokens - Optional custom tokens to replace in format string.
   */
  tick(amount = 1, tokens) {
    this.update(this.current + amount, tokens);
  }
  /**
   * Render the progress bar.
   */
  render(tokens) {
    const colorName = this.options.color ?? "cyan";
    const colorFn = import_yoctocolors_cjs.default[colorName] || ((s) => s);
    const percent = this.total === 0 ? 0 : (0, import_math.MathFloor)(this.current / this.total * 100);
    const elapsed = (0, import_date.DateNow)() - this.startTime;
    const eta = this.current === 0 ? 0 : elapsed / this.current * (this.total - this.current);
    const availableWidth = this.options.width ?? 40;
    const filledWidth = this.total === 0 ? 0 : (0, import_math.MathMin)(
      availableWidth,
      Math.floor(this.current / this.total * availableWidth)
    );
    const emptyWidth = (0, import_math.MathMax)(0, availableWidth - filledWidth);
    const filled = (0, import_format.repeatString)(this.options.complete ?? "\u2588", filledWidth);
    const empty = (0, import_format.repeatString)(this.options.incomplete ?? "\u2591", emptyWidth);
    const bar = colorFn(filled) + empty;
    let output = this.options.format ?? ":bar :percent :current/:total";
    output = (0, import_string.StringPrototypeReplace)(output, ":bar", bar);
    output = output.replace(":percent", `${percent}%`);
    output = output.replace(":current", String(this.current));
    output = output.replace(":total", String(this.total));
    output = output.replace(":elapsed", this.formatTime(elapsed));
    output = output.replace(":eta", this.formatTime(eta));
    if (tokens) {
      for (const [key, value] of (0, import_object.ObjectEntries)(tokens)) {
        output = output.replace(`:${key}`, String(value));
      }
    }
    this.clearLine();
    this.stream.write(output);
    this.lastDrawnWidth = (0, import_strip.stripAnsi)(output).length;
  }
  /**
   * Clear the current line.
   */
  clearLine() {
    if (this.stream.isTTY) {
      this.stream.cursorTo(0);
      this.stream.clearLine(0);
    } else if (this.lastDrawnWidth > 0) {
      this.stream.write(`\r${(0, import_format.repeatString)(" ", this.lastDrawnWidth)}\r`);
    }
  }
  /**
   * Format time in seconds to human readable.
   */
  formatTime(ms) {
    const seconds = (0, import_math.MathMax)(0, Math.round(ms / 1e3));
    if (seconds < 60) {
      return `${seconds}s`;
    }
    const minutes = (0, import_math.MathFloor)(seconds / 60);
    const remainingSeconds = seconds % 60;
    return `${minutes}m${remainingSeconds}s`;
  }
  /**
   * Terminate the progress bar and optionally clear it. Called automatically
   * when progress reaches 100%. If `clear` option is true, removes the bar from
   * terminal. Otherwise, moves to next line to preserve the final state.
   */
  terminate() {
    if (this.terminated) {
      return;
    }
    this.terminated = true;
    if (this.options.clear) {
      this.clearLine();
    } else {
      this.stream.write("\n");
    }
  }
}
function createProgressIndicator(current, total, label) {
  const percent = total === 0 ? 0 : (0, import_math.MathFloor)(current / total * 100);
  const progress = `${current}/${total}`;
  let output = "";
  if (label) {
    output += `${label}: `;
  }
  output += `${import_yoctocolors_cjs.default.cyan(`[${percent}%]`)} ${progress}`;
  return output;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  ProgressBar,
  createProgressIndicator
});
