/* Socket Lib - Built with esbuild */
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, desc2) => {
  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: !(desc2 = __getOwnPropDesc(from, key)) || desc2.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 spinner_exports = {};
__export(spinner_exports, {
  Spinner: () => Spinner,
  ciSpinner: () => ciSpinner,
  getCliSpinners: () => getCliSpinners,
  getDefaultSpinner: () => getDefaultSpinner,
  spinner: () => spinner,
  withSpinner: () => withSpinner,
  withSpinnerRestore: () => withSpinnerRestore,
  withSpinnerSync: () => withSpinnerSync
});
module.exports = __toCommonJS(spinner_exports);
var import_ci = require("#env/ci");
var import_pulse_frames = require("./effects/pulse-frames");
var import_text_shimmer = require("./effects/text-shimmer");
var import_yocto_spinner = __toESM(require("./external/@socketregistry/yocto-spinner"));
var import_objects = require("./objects");
var import_strings = require("./strings");
const colorToRgb = {
  __proto__: null,
  black: [0, 0, 0],
  blue: [0, 0, 255],
  blueBright: [100, 149, 237],
  cyan: [0, 255, 255],
  cyanBright: [0, 255, 255],
  gray: [128, 128, 128],
  green: [0, 128, 0],
  greenBright: [0, 255, 0],
  magenta: [255, 0, 255],
  magentaBright: [255, 105, 180],
  red: [255, 0, 0],
  redBright: [255, 69, 0],
  white: [255, 255, 255],
  whiteBright: [255, 255, 255],
  yellow: [255, 255, 0],
  yellowBright: [255, 255, 153]
};
function isRgbTuple(value) {
  return Array.isArray(value);
}
function toRgb(color) {
  if (isRgbTuple(color)) {
    return color;
  }
  return colorToRgb[color];
}
const ciSpinner = {
  frames: [""],
  interval: 2147483647
};
function desc(value) {
  return {
    __proto__: null,
    configurable: true,
    value,
    writable: true
  };
}
function normalizeText(value) {
  return typeof value === "string" ? value.trimStart() : "";
}
function formatProgress(progress) {
  const { current, total, unit } = progress;
  const percentage = Math.round(current / total * 100);
  const bar = renderProgressBar(percentage);
  const count = unit ? `${current}/${total} ${unit}` : `${current}/${total}`;
  return `${bar} ${percentage}% (${count})`;
}
function renderProgressBar(percentage, width = 20) {
  const filled = Math.round(percentage / 100 * width);
  const empty = width - filled;
  const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
  const colors = require("../external/yoctocolors-cjs");
  return colors.cyan(bar);
}
let _cliSpinners;
// @__NO_SIDE_EFFECTS__
function getCliSpinners(styleName) {
  if (_cliSpinners === void 0) {
    const YoctoCtor = import_yocto_spinner.default;
    const tempInstance = YoctoCtor({});
    const YoctoSpinnerClass = tempInstance.constructor;
    _cliSpinners = {
      __proto__: null,
      ...YoctoSpinnerClass.spinners,
      socket: (0, import_pulse_frames.generateSocketSpinnerFrames)()
    };
  }
  if (typeof styleName === "string" && _cliSpinners) {
    return (0, import_objects.hasOwn)(_cliSpinners, styleName) ? _cliSpinners[styleName] : void 0;
  }
  return _cliSpinners;
}
let _Spinner;
let _defaultSpinner;
// @__NO_SIDE_EFFECTS__
function Spinner(options) {
  if (_Spinner === void 0) {
    const YoctoCtor = import_yocto_spinner.default;
    const tempInstance = YoctoCtor({});
    const YoctoSpinnerClass = tempInstance.constructor;
    _Spinner = class SpinnerClass extends YoctoSpinnerClass {
      #baseText = "";
      #indentation = "";
      #progress;
      #shimmer;
      #shimmerSavedConfig;
      constructor(options2) {
        const opts = { __proto__: null, ...options2 };
        const spinnerColor = opts.color ?? [140, 82, 255];
        if (isRgbTuple(spinnerColor) && (spinnerColor.length !== 3 || !spinnerColor.every(
          (n) => typeof n === "number" && n >= 0 && n <= 255
        ))) {
          throw new TypeError(
            "RGB color must be an array of 3 numbers between 0 and 255"
          );
        }
        const spinnerColorRgb = toRgb(spinnerColor);
        let shimmerInfo;
        if (opts.shimmer) {
          let shimmerDir;
          let shimmerColor;
          let shimmerSpeed = 1 / 3;
          if (typeof opts.shimmer === "string") {
            shimmerDir = opts.shimmer;
          } else {
            const shimmerConfig = {
              __proto__: null,
              ...opts.shimmer
            };
            shimmerDir = shimmerConfig.dir ?? import_text_shimmer.DIR_LTR;
            shimmerColor = shimmerConfig.color ?? import_text_shimmer.COLOR_INHERIT;
            shimmerSpeed = shimmerConfig.speed ?? 1 / 3;
          }
          shimmerInfo = {
            __proto__: null,
            color: shimmerColor === void 0 ? import_text_shimmer.COLOR_INHERIT : shimmerColor,
            currentDir: import_text_shimmer.DIR_LTR,
            mode: shimmerDir,
            speed: shimmerSpeed,
            step: 0
          };
        }
        super({
          signal: require("#constants/process").getAbortSignal(),
          ...opts,
          // Pass RGB color directly to yocto-spinner (it now supports RGB).
          color: spinnerColorRgb,
          // onRenderFrame callback provides full control over frame + text layout.
          // Calculates spacing based on frame width to prevent text jumping.
          onRenderFrame: (frame, text, applyColor) => {
            const width = (0, import_strings.stringWidth)(frame);
            const spacing = width === 1 ? "  " : " ";
            return frame ? `${applyColor(frame)}${spacing}${text}` : text;
          },
          // onFrameUpdate callback is called by yocto-spinner whenever a frame advances.
          // This ensures shimmer updates are perfectly synchronized with animation beats.
          onFrameUpdate: shimmerInfo ? () => {
            if (this.#baseText) {
              super.text = this.#buildDisplayText();
            }
          } : void 0
        });
        this.#shimmer = shimmerInfo;
        this.#shimmerSavedConfig = shimmerInfo;
      }
      // Override color getter to ensure it's always RGB.
      get color() {
        const value = super.color;
        return isRgbTuple(value) ? value : toRgb(value);
      }
      // Override color setter to always convert to RGB before passing to yocto-spinner.
      set color(value) {
        super.color = isRgbTuple(value) ? value : toRgb(value);
      }
      /**
       * Apply a yocto-spinner method and update logger state.
       * Handles text normalization, extra arguments, and logger tracking.
       * @private
       */
      #apply(methodName, args) {
        let extras;
        let text = args.at(0);
        if (typeof text === "string") {
          extras = args.slice(1);
        } else {
          extras = args;
          text = "";
        }
        const wasSpinning = this.isSpinning;
        const normalized = normalizeText(text);
        super[methodName](normalized);
        const {
          incLogCallCountSymbol,
          lastWasBlankSymbol,
          logger
        } = require("./logger.js");
        if (methodName === "stop") {
          if (wasSpinning && normalized) {
            logger[lastWasBlankSymbol]((0, import_strings.isBlankString)(normalized));
            logger[incLogCallCountSymbol]();
          }
        } else {
          logger[lastWasBlankSymbol](false);
          logger[incLogCallCountSymbol]();
        }
        if (extras.length) {
          logger.log(...extras);
          logger[lastWasBlankSymbol](false);
        }
        return this;
      }
      /**
       * Build the complete display text with progress, shimmer, and indentation.
       * Combines base text, progress bar, shimmer effects, and indentation.
       * @private
       */
      #buildDisplayText() {
        let displayText = this.#baseText;
        if (this.#progress) {
          const progressText = formatProgress(this.#progress);
          displayText = displayText ? `${displayText} ${progressText}` : progressText;
        }
        if (displayText && this.#shimmer) {
          let shimmerColor;
          if (this.#shimmer.color === import_text_shimmer.COLOR_INHERIT) {
            shimmerColor = this.color;
          } else if (Array.isArray(this.#shimmer.color[0])) {
            shimmerColor = this.#shimmer.color;
          } else {
            shimmerColor = toRgb(this.#shimmer.color);
          }
          displayText = (0, import_text_shimmer.applyShimmer)(displayText, this.#shimmer, {
            color: shimmerColor,
            direction: this.#shimmer.mode
          });
        }
        if (this.#indentation && displayText) {
          displayText = this.#indentation + displayText;
        }
        return displayText;
      }
      /**
       * Show a status message without stopping the spinner.
       * Outputs the symbol and message to stderr, then continues spinning.
       */
      #showStatusAndKeepSpinning(symbolType, args) {
        let text = args.at(0);
        let extras;
        if (typeof text === "string") {
          extras = args.slice(1);
        } else {
          extras = args;
          text = "";
        }
        const { LOG_SYMBOLS, logger } = require("./logger.js");
        logger.error(`${LOG_SYMBOLS[symbolType]} ${text}`, ...extras);
        return this;
      }
      /**
       * Update the spinner's displayed text.
       * Rebuilds display text and triggers render.
       * @private
       */
      #updateSpinnerText() {
        super.text = this.#buildDisplayText();
      }
      /**
       * Show a debug message without stopping the spinner (only if debug mode enabled).
       * Outputs to stderr and continues spinning.
       */
      debug(...args) {
        const { isDebug } = require("./debug.js");
        if (isDebug()) {
          return this.#showStatusAndKeepSpinning("info", args);
        }
        return this;
      }
      /**
       * Show a debug message and stop the spinner (only if debug mode enabled).
       * Auto-clears the spinner line before displaying the message.
       */
      debugAndStop(...args) {
        const { isDebug } = require("./debug.js");
        if (isDebug()) {
          return this.#apply("info", args);
        }
        return this;
      }
      /**
       * Decrease indentation level.
       * Pass 0 to reset indentation to zero.
       * @param spaces - Number of spaces to remove (default: 2)
       */
      dedent(spaces) {
        if (spaces === 0) {
          this.#indentation = "";
        } else {
          const amount = spaces ?? 2;
          const newLength = Math.max(0, this.#indentation.length - amount);
          this.#indentation = this.#indentation.slice(0, newLength);
        }
        this.#updateSpinnerText();
        return this;
      }
      /**
       * Alias for success() (shorter name).
       * DESIGN DECISION: Unlike yocto-spinner, our done() does NOT stop the spinner.
       * Use doneAndStop() if you want to stop the spinner.
       */
      done(...args) {
        return this.#showStatusAndKeepSpinning("success", args);
      }
      /**
       * Show a done message and stop the spinner.
       * Auto-clears the spinner line before displaying the success message.
       */
      doneAndStop(...args) {
        return this.#apply("success", args);
      }
      /**
       * Show a failure message without stopping the spinner.
       * DESIGN DECISION: Unlike yocto-spinner, our fail() does NOT stop the spinner.
       * This allows displaying errors while continuing to spin.
       * Use failAndStop() if you want to stop the spinner.
       */
      fail(...args) {
        return this.#showStatusAndKeepSpinning("fail", args);
      }
      /**
       * Show a failure message and stop the spinner.
       * Auto-clears the spinner line before displaying the error message.
       */
      failAndStop(...args) {
        return this.#apply("error", args);
      }
      /**
       * Increase indentation level.
       * Pass 0 to reset indentation to zero.
       * @param spaces - Number of spaces to add (default: 2)
       */
      indent(spaces) {
        if (spaces === 0) {
          this.#indentation = "";
        } else {
          const amount = spaces ?? 2;
          this.#indentation += " ".repeat(amount);
        }
        this.#updateSpinnerText();
        return this;
      }
      /**
       * Show an info message without stopping the spinner.
       * Outputs to stderr and continues spinning.
       */
      info(...args) {
        return this.#showStatusAndKeepSpinning("info", args);
      }
      /**
       * Show an info message and stop the spinner.
       * Auto-clears the spinner line before displaying the message.
       */
      infoAndStop(...args) {
        return this.#apply("info", args);
      }
      /**
       * Log a message to stdout without stopping the spinner.
       * Unlike other methods, this outputs to stdout for data logging.
       */
      log(...args) {
        const { logger } = require("./logger.js");
        logger.log(...args);
        return this;
      }
      /**
       * Log a message and stop the spinner.
       * Auto-clears the spinner line before displaying the message.
       */
      logAndStop(...args) {
        return this.#apply("stop", args);
      }
      /**
       * Update progress information displayed with the spinner.
       * Shows a progress bar with percentage and optional unit label.
       * @param current - Current progress value
       * @param total - Total progress value
       * @param unit - Optional unit label (e.g., 'files', 'items')
       */
      progress = (current, total, unit) => {
        this.#progress = {
          __proto__: null,
          current,
          total,
          ...unit ? { unit } : {}
        };
        this.#updateSpinnerText();
        return this;
      };
      /**
       * Increment progress by a specified amount.
       * Updates the progress bar displayed with the spinner.
       * @param amount - Amount to increment (default: 1)
       */
      progressStep(amount = 1) {
        if (this.#progress) {
          const newCurrent = this.#progress.current + amount;
          this.#progress = {
            __proto__: null,
            current: Math.max(0, Math.min(newCurrent, this.#progress.total)),
            total: this.#progress.total,
            ...this.#progress.unit ? { unit: this.#progress.unit } : {}
          };
          this.#updateSpinnerText();
        }
        return this;
      }
      /**
       * Start the spinner animation with optional text.
       * Begins displaying the animated spinner.
       * @param text - Optional text to display with the spinner
       */
      start(...args) {
        if (args.length) {
          const text = args.at(0);
          const normalized = normalizeText(text);
          if (!normalized) {
            this.#baseText = "";
            super.text = "";
          } else {
            this.#baseText = normalized;
          }
        }
        this.#updateSpinnerText();
        return this.#apply("start", args);
      }
      /**
       * Log a main step message to stderr without stopping the spinner.
       * Adds a blank line before the message for visual separation.
       * Aligns with logger.step() to use stderr for status messages.
       */
      step(...args) {
        const text = args[0];
        const { logger } = require("./logger.js");
        if (typeof text === "string") {
          logger.error("");
          logger.error(text, ...args.slice(1));
        }
        return this;
      }
      /**
       * Log an indented substep message to stderr without stopping the spinner.
       * Adds 2-space indentation to the message.
       * Aligns with logger.substep() to use stderr for status messages.
       */
      substep(...args) {
        const text = args[0];
        if (typeof text === "string") {
          const { logger } = require("./logger.js");
          logger.error(`  ${text}`, ...args.slice(1));
        }
        return this;
      }
      /**
       * Stop the spinner animation and clear internal state.
       * Auto-clears the spinner line via yocto-spinner.stop().
       * Resets progress, shimmer, and text state.
       * @param text - Optional final text to display after stopping
       */
      stop(...args) {
        this.#baseText = "";
        this.#progress = void 0;
        if (this.#shimmer) {
          this.#shimmer.currentDir = import_text_shimmer.DIR_LTR;
          this.#shimmer.step = 0;
        }
        const result = this.#apply("stop", args);
        super.text = "";
        return result;
      }
      /**
       * Show a success message without stopping the spinner.
       * DESIGN DECISION: Unlike yocto-spinner, our success() does NOT stop the spinner.
       * This allows displaying success messages while continuing to spin for multi-step operations.
       * Use successAndStop() if you want to stop the spinner.
       */
      success(...args) {
        return this.#showStatusAndKeepSpinning("success", args);
      }
      /**
       * Show a success message and stop the spinner.
       * Auto-clears the spinner line before displaying the success message.
       */
      successAndStop(...args) {
        return this.#apply("success", args);
      }
      text(value) {
        if (arguments.length === 0) {
          return this.#baseText;
        }
        this.#baseText = value ?? "";
        this.#updateSpinnerText();
        return this;
      }
      /**
       * Show a warning message without stopping the spinner.
       * Outputs to stderr and continues spinning.
       */
      warn(...args) {
        return this.#showStatusAndKeepSpinning("warn", args);
      }
      /**
       * Show a warning message and stop the spinner.
       * Auto-clears the spinner line before displaying the warning message.
       */
      warnAndStop(...args) {
        return this.#apply("warning", args);
      }
      /**
       * Toggle shimmer effect or update shimmer configuration.
       * Preserves shimmer config when toggling off, allowing easy re-enable.
       * Supports partial config updates to tweak specific properties.
       *
       * @param enabledOrConfig - Boolean to toggle, partial config to update, or direction string
       * @returns This spinner for chaining
       *
       * @example
       * // Toggle off (preserves config for later re-enable)
       * spinner.shimmer(false)
       *
       * // Toggle on (restores saved config or uses defaults)
       * spinner.shimmer(true)
       *
       * // Update specific properties
       * spinner.shimmer({ speed: 0.5 })
       * spinner.shimmer({ color: [255, 0, 0] })
       *
       * // Set direction
       * spinner.shimmer('rtl')
       */
      shimmer(enabledOrConfig) {
        if (enabledOrConfig === false) {
          this.#shimmer = void 0;
        } else if (enabledOrConfig === true) {
          if (this.#shimmerSavedConfig) {
            this.#shimmer = { ...this.#shimmerSavedConfig };
          } else {
            this.#shimmer = {
              color: import_text_shimmer.COLOR_INHERIT,
              currentDir: import_text_shimmer.DIR_LTR,
              mode: import_text_shimmer.DIR_LTR,
              speed: 1 / 3,
              step: 0
            };
            this.#shimmerSavedConfig = this.#shimmer;
          }
        } else if (typeof enabledOrConfig === "string") {
          if (this.#shimmer) {
            this.#shimmer = {
              ...this.#shimmer,
              mode: enabledOrConfig
            };
            this.#shimmerSavedConfig = this.#shimmer;
          } else if (this.#shimmerSavedConfig) {
            this.#shimmer = {
              ...this.#shimmerSavedConfig,
              mode: enabledOrConfig
            };
            this.#shimmerSavedConfig = this.#shimmer;
          } else {
            this.#shimmer = {
              color: import_text_shimmer.COLOR_INHERIT,
              currentDir: import_text_shimmer.DIR_LTR,
              mode: enabledOrConfig,
              speed: 1 / 3,
              step: 0
            };
            this.#shimmerSavedConfig = this.#shimmer;
          }
        } else if (enabledOrConfig && typeof enabledOrConfig === "object") {
          const partialConfig = {
            __proto__: null,
            ...enabledOrConfig
          };
          if (this.#shimmer) {
            this.#shimmer = {
              ...this.#shimmer,
              ...partialConfig.color !== void 0 ? { color: partialConfig.color } : {},
              ...partialConfig.dir !== void 0 ? { mode: partialConfig.dir } : {},
              ...partialConfig.speed !== void 0 ? { speed: partialConfig.speed } : {}
            };
            this.#shimmerSavedConfig = this.#shimmer;
          } else if (this.#shimmerSavedConfig) {
            this.#shimmer = {
              ...this.#shimmerSavedConfig,
              ...partialConfig.color !== void 0 ? { color: partialConfig.color } : {},
              ...partialConfig.dir !== void 0 ? { mode: partialConfig.dir } : {},
              ...partialConfig.speed !== void 0 ? { speed: partialConfig.speed } : {}
            };
            this.#shimmerSavedConfig = this.#shimmer;
          } else {
            this.#shimmer = {
              color: partialConfig.color ?? import_text_shimmer.COLOR_INHERIT,
              currentDir: import_text_shimmer.DIR_LTR,
              mode: partialConfig.dir ?? import_text_shimmer.DIR_LTR,
              speed: partialConfig.speed ?? 1 / 3,
              step: 0
            };
            this.#shimmerSavedConfig = this.#shimmer;
          }
        }
        this.#updateSpinnerText();
        return this;
      }
    };
    Object.defineProperties(_Spinner.prototype, {
      error: desc(_Spinner.prototype.fail),
      errorAndStop: desc(_Spinner.prototype.failAndStop),
      warning: desc(_Spinner.prototype.warn),
      warningAndStop: desc(_Spinner.prototype.warnAndStop)
    });
    _defaultSpinner = import_ci.CI ? ciSpinner : /* @__PURE__ */ getCliSpinners("socket");
  }
  return new _Spinner({
    spinner: _defaultSpinner,
    ...options
  });
}
let _spinner;
function getDefaultSpinner() {
  if (_spinner === void 0) {
    _spinner = /* @__PURE__ */ Spinner();
  }
  return _spinner;
}
const spinner = /* @__PURE__ */ (() => {
  let _lazySpinner;
  return new Proxy({}, {
    get(_target, prop) {
      if (_lazySpinner === void 0) {
        _lazySpinner = /* @__PURE__ */ Spinner();
      }
      const value = _lazySpinner[prop];
      return typeof value === "function" ? value.bind(_lazySpinner) : value;
    }
  });
})();
async function withSpinner(options) {
  const { message, operation, spinner: spinner2 } = {
    __proto__: null,
    ...options
  };
  if (!spinner2) {
    return await operation();
  }
  spinner2.start(message);
  try {
    return await operation();
  } finally {
    spinner2.stop();
  }
}
async function withSpinnerRestore(options) {
  const { operation, spinner: spinner2, wasSpinning } = {
    __proto__: null,
    ...options
  };
  try {
    return await operation();
  } finally {
    if (spinner2 && wasSpinning) {
      spinner2.start();
    }
  }
}
function withSpinnerSync(options) {
  const { message, operation, spinner: spinner2 } = {
    __proto__: null,
    ...options
  };
  if (!spinner2) {
    return operation();
  }
  spinner2.start(message);
  try {
    return operation();
  } finally {
    spinner2.stop();
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  Spinner,
  ciSpinner,
  getCliSpinners,
  getDefaultSpinner,
  spinner,
  withSpinner,
  withSpinnerRestore,
  withSpinnerSync
});
//# sourceMappingURL=spinner.js.map
