/* 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, 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 logger_exports = {};
__export(logger_exports, {
  LOG_SYMBOLS: () => LOG_SYMBOLS,
  Logger: () => Logger,
  incLogCallCountSymbol: () => incLogCallCountSymbol,
  lastWasBlankSymbol: () => lastWasBlankSymbol,
  logger: () => logger
});
module.exports = __toCommonJS(logger_exports);
var import_is_unicode_supported = __toESM(require("./external/@socketregistry/is-unicode-supported"));
var import_yoctocolors_cjs = __toESM(require("./external/yoctocolors-cjs"));
var import_objects = require("./objects");
var import_strings = require("./strings");
const globalConsole = console;
const ReflectApply = Reflect.apply;
const ReflectConstruct = Reflect.construct;
let _Console;
// @__NO_SIDE_EFFECTS__
function constructConsole(...args) {
  if (_Console === void 0) {
    const nodeConsole = require("node:console");
    _Console = nodeConsole.Console;
  }
  return ReflectConstruct(
    // biome-ignore lint/style/noNonNullAssertion: Initialized above.
    _Console,
    // eslint-disable-line no-undef
    args
  );
}
// @__NO_SIDE_EFFECTS__
function getYoctocolors() {
  return import_yoctocolors_cjs.default;
}
const LOG_SYMBOLS = /* @__PURE__ */ (() => {
  const target = {
    __proto__: null
  };
  const handler = {
    __proto__: null
  };
  const init = () => {
    const supported = (0, import_is_unicode_supported.default)();
    const colors = /* @__PURE__ */ getYoctocolors();
    (0, import_objects.objectAssign)(target, {
      fail: colors.red(supported ? "\u2716" : "\xD7"),
      info: colors.blue(supported ? "\u2139" : "i"),
      success: colors.green(supported ? "\u2714" : "\u221A"),
      warn: colors.yellow(supported ? "\u26A0" : "\u203C")
    });
    (0, import_objects.objectFreeze)(target);
    for (const trapName in handler) {
      delete handler[trapName];
    }
  };
  for (const trapName of Reflect.ownKeys(Reflect)) {
    const fn = Reflect[trapName];
    if (typeof fn === "function") {
      ;
      handler[trapName] = (...args) => {
        init();
        return fn(...args);
      };
    }
  }
  return new Proxy(target, handler);
})();
const boundConsoleEntries = [
  // Add bound properties from console[kBindProperties](ignoreErrors, colorMode, groupIndentation).
  // https://github.com/nodejs/node/blob/v24.0.1/lib/internal/console/constructor.js#L230-L265
  "_stderrErrorHandler",
  "_stdoutErrorHandler",
  // Add methods that need to be bound to function properly.
  "assert",
  "clear",
  "count",
  "countReset",
  "createTask",
  "debug",
  "dir",
  "dirxml",
  "error",
  // Skip group methods because in at least Node 20 with the Node --frozen-intrinsics
  // flag it triggers a readonly property for Symbol(kGroupIndent). Instead, we
  // implement these methods ourselves.
  //'group',
  //'groupCollapsed',
  //'groupEnd',
  "info",
  "log",
  "table",
  "time",
  "timeEnd",
  "timeLog",
  "trace",
  "warn"
].filter((n) => typeof globalConsole[n] === "function").map((n) => [n, globalConsole[n].bind(globalConsole)]);
const consolePropAttributes = {
  __proto__: null,
  writable: true,
  enumerable: false,
  configurable: true
};
const maxIndentation = 1e3;
const privateConsole = /* @__PURE__ */ new WeakMap();
const consoleSymbols = Object.getOwnPropertySymbols(globalConsole);
const incLogCallCountSymbol = Symbol.for("logger.logCallCount++");
const kGroupIndentationWidthSymbol = (
  // biome-ignore lint/suspicious/noExplicitAny: Symbol property access.
  consoleSymbols.find((s) => s.label === "kGroupIndentWidth") ?? Symbol("kGroupIndentWidth")
);
const lastWasBlankSymbol = Symbol.for("logger.lastWasBlank");
class Logger {
  static LOG_SYMBOLS = LOG_SYMBOLS;
  #parent;
  #boundStream;
  #stderrLogger;
  #stdoutLogger;
  #stderrIndention = "";
  #stdoutIndention = "";
  #lastWasBlank = false;
  #logCallCount = 0;
  #constructorArgs;
  #options;
  constructor(...args) {
    this.#constructorArgs = args;
    const options = args["0"];
    if (typeof options === "object" && options !== null) {
      this.#options = { __proto__: null, ...options };
    } else {
      this.#options = { __proto__: null };
    }
    if (args.length) {
      privateConsole.set(this, /* @__PURE__ */ constructConsole(...args));
    } else {
      const con = /* @__PURE__ */ constructConsole({
        stdout: process.stdout,
        stderr: process.stderr
      });
      for (const { 0: key, 1: method } of boundConsoleEntries) {
        con[key] = method;
      }
      privateConsole.set(this, con);
    }
  }
  /**
   * Get a logger instance bound to stderr.
   * All operations on this instance will use stderr.
   */
  get stderr() {
    if (!this.#stderrLogger) {
      const instance = new Logger(...this.#constructorArgs);
      instance.#parent = this;
      instance.#boundStream = "stderr";
      instance.#options = { __proto__: null, ...this.#options };
      this.#stderrLogger = instance;
    }
    return this.#stderrLogger;
  }
  /**
   * Get a logger instance bound to stdout.
   * All operations on this instance will use stdout.
   */
  get stdout() {
    if (!this.#stdoutLogger) {
      const instance = new Logger(...this.#constructorArgs);
      instance.#parent = this;
      instance.#boundStream = "stdout";
      instance.#options = { __proto__: null, ...this.#options };
      this.#stdoutLogger = instance;
    }
    return this.#stdoutLogger;
  }
  /**
   * Get the root logger (for accessing shared indentation state).
   * @private
   */
  #getRoot() {
    return this.#parent || this;
  }
  /**
   * Get indentation for a specific stream.
   * @private
   */
  #getIndent(stream) {
    const root = this.#getRoot();
    return stream === "stderr" ? root.#stderrIndention : root.#stdoutIndention;
  }
  /**
   * Set indentation for a specific stream.
   * @private
   */
  #setIndent(stream, value) {
    const root = this.#getRoot();
    if (stream === "stderr") {
      root.#stderrIndention = value;
    } else {
      root.#stdoutIndention = value;
    }
  }
  /**
   * Get the target stream for this logger instance.
   * @private
   */
  #getTargetStream() {
    return this.#boundStream || "stderr";
  }
  /**
   * Apply a console method with indentation.
   * @private
   */
  #apply(methodName, args, stream) {
    const con = privateConsole.get(this);
    const text = args.at(0);
    const hasText = typeof text === "string";
    const targetStream = stream || (methodName === "log" ? "stdout" : "stderr");
    const indent = this.#getIndent(targetStream);
    const logArgs = hasText ? [(0, import_strings.applyLinePrefix)(text, { prefix: indent }), ...args.slice(1)] : args;
    ReflectApply(
      con[methodName],
      con,
      logArgs
    );
    this[lastWasBlankSymbol](hasText && (0, import_strings.isBlankString)(logArgs[0]));
    this[incLogCallCountSymbol]();
    return this;
  }
  /**
   * Strip log symbols from the start of text.
   * @private
   */
  #stripSymbols(text) {
    return text.replace(/^[✖×⚠‼✔√ℹ]\uFE0F?\s*/u, "");
  }
  /**
   * Apply a method with a symbol prefix.
   * @private
   */
  #symbolApply(symbolType, args) {
    const con = privateConsole.get(this);
    let text = args.at(0);
    let extras;
    if (typeof text === "string") {
      text = this.#stripSymbols(text);
      extras = args.slice(1);
    } else {
      extras = args;
      text = "";
    }
    const indent = this.#getIndent("stderr");
    con.error(
      (0, import_strings.applyLinePrefix)(`${LOG_SYMBOLS[symbolType]} ${text}`, {
        prefix: indent
      }),
      ...extras
    );
    this.#lastWasBlank = false;
    this[incLogCallCountSymbol]();
    return this;
  }
  /**
   * Get the current log call count.
   */
  get logCallCount() {
    return this.#logCallCount;
  }
  /**
   * Increment the log call count.
   */
  [incLogCallCountSymbol]() {
    this.#logCallCount += 1;
    return this;
  }
  /**
   * Set whether the last logged line was blank.
   */
  [lastWasBlankSymbol](value) {
    this.#lastWasBlank = !!value;
    return this;
  }
  /**
   * Log an assertion.
   */
  assert(value, ...message) {
    const con = privateConsole.get(this);
    con.assert(value, ...message);
    this[lastWasBlankSymbol](false);
    return value ? this : this[incLogCallCountSymbol]();
  }
  /**
   * Clear the visible terminal screen.
   * Only available on the main logger instance.
   */
  clearVisible() {
    if (this.#boundStream) {
      throw new Error(
        "clearVisible() is only available on the main logger instance, not on stream-bound instances"
      );
    }
    const con = privateConsole.get(this);
    con.clear();
    if (con._stdout.isTTY) {
      ;
      this[lastWasBlankSymbol](true);
      this.#logCallCount = 0;
    }
    return this;
  }
  /**
   * Log a count for the given label.
   */
  count(label) {
    const con = privateConsole.get(this);
    con.count(label);
    this[lastWasBlankSymbol](false);
    return this[incLogCallCountSymbol]();
  }
  /**
   * Create a task with a given name.
   */
  createTask(name) {
    return {
      run: (f) => {
        this.log(`Starting task: ${name}`);
        const result = f();
        this.log(`Completed task: ${name}`);
        return result;
      }
    };
  }
  /**
   * Decrease indentation level.
   * If called on main logger, affects both streams.
   * If called on stream-bound logger, affects only that stream.
   */
  dedent(spaces = 2) {
    if (this.#boundStream) {
      const current = this.#getIndent(this.#boundStream);
      this.#setIndent(this.#boundStream, current.slice(0, -spaces));
    } else {
      const stderrCurrent = this.#getIndent("stderr");
      const stdoutCurrent = this.#getIndent("stdout");
      this.#setIndent("stderr", stderrCurrent.slice(0, -spaces));
      this.#setIndent("stdout", stdoutCurrent.slice(0, -spaces));
    }
    return this;
  }
  /**
   * Display an object's properties.
   */
  dir(obj, options) {
    const con = privateConsole.get(this);
    con.dir(obj, options);
    this[lastWasBlankSymbol](false);
    return this[incLogCallCountSymbol]();
  }
  /**
   * Display data as XML.
   */
  dirxml(...data) {
    const con = privateConsole.get(this);
    con.dirxml(data);
    this[lastWasBlankSymbol](false);
    return this[incLogCallCountSymbol]();
  }
  /**
   * Log an error message.
   */
  error(...args) {
    return this.#apply("error", args);
  }
  /**
   * Log a newline to stderr if last line wasn't blank.
   */
  errorNewline() {
    return this.#lastWasBlank ? this : this.error("");
  }
  /**
   * Log a failure message with symbol.
   */
  fail(...args) {
    return this.#symbolApply("fail", args);
  }
  /**
   * Start a new log group.
   */
  group(...label) {
    const { length } = label;
    if (length) {
      ReflectApply(this.log, this, label);
    }
    this.indent(this[kGroupIndentationWidthSymbol]);
    if (length) {
      ;
      this[lastWasBlankSymbol](false);
      this[incLogCallCountSymbol]();
    }
    return this;
  }
  /**
   * Start a new collapsed log group (alias for group).
   */
  // groupCollapsed is an alias of group.
  // https://nodejs.org/api/console.html#consolegroupcollapsed
  groupCollapsed(...label) {
    return ReflectApply(this.group, this, label);
  }
  /**
   * End the current log group.
   */
  groupEnd() {
    this.dedent(this[kGroupIndentationWidthSymbol]);
    return this;
  }
  /**
   * Increase indentation level.
   * If called on main logger, affects both streams.
   * If called on stream-bound logger, affects only that stream.
   */
  indent(spaces = 2) {
    const spacesToAdd = " ".repeat(Math.min(spaces, maxIndentation));
    if (this.#boundStream) {
      const current = this.#getIndent(this.#boundStream);
      this.#setIndent(this.#boundStream, current + spacesToAdd);
    } else {
      const stderrCurrent = this.#getIndent("stderr");
      const stdoutCurrent = this.#getIndent("stdout");
      this.#setIndent("stderr", stderrCurrent + spacesToAdd);
      this.#setIndent("stdout", stdoutCurrent + spacesToAdd);
    }
    return this;
  }
  /**
   * Log an info message with symbol.
   */
  info(...args) {
    return this.#symbolApply("info", args);
  }
  /**
   * Log a message.
   */
  log(...args) {
    return this.#apply("log", args);
  }
  /**
   * Log a newline to stdout if last line wasn't blank.
   */
  logNewline() {
    return this.#lastWasBlank ? this : this.log("");
  }
  /**
   * Reset indentation to zero.
   * If called on main logger, resets both streams.
   * If called on stream-bound logger, resets only that stream.
   */
  resetIndent() {
    if (this.#boundStream) {
      this.#setIndent(this.#boundStream, "");
    } else {
      this.#setIndent("stderr", "");
      this.#setIndent("stdout", "");
    }
    return this;
  }
  /**
   * Log a main step with blank line before (stateless).
   */
  step(msg, ...extras) {
    if (!this.#lastWasBlank) {
      this.log("");
    }
    return this.log(msg, ...extras);
  }
  /**
   * Log an indented substep (stateless).
   */
  substep(msg, ...extras) {
    const indentedMsg = `  ${msg}`;
    return this.log(indentedMsg, ...extras);
  }
  /**
   * Log a success message with symbol.
   */
  success(...args) {
    return this.#symbolApply("success", args);
  }
  /**
   * Log a done message (alias for success).
   * Does NOT auto-clear. Call clearLine() first if needed after progress().
   */
  done(...args) {
    return this.#symbolApply("success", args);
  }
  /**
   * Display data in a table format.
   */
  table(tabularData, properties) {
    const con = privateConsole.get(this);
    con.table(tabularData, properties);
    this[lastWasBlankSymbol](false);
    return this[incLogCallCountSymbol]();
  }
  /**
   * End a timer and log the elapsed time.
   */
  timeEnd(label) {
    const con = privateConsole.get(this);
    con.timeEnd(label);
    this[lastWasBlankSymbol](false);
    return this[incLogCallCountSymbol]();
  }
  /**
   * Log the current timer value.
   */
  timeLog(label, ...data) {
    const con = privateConsole.get(this);
    con.timeLog(label, ...data);
    this[lastWasBlankSymbol](false);
    return this[incLogCallCountSymbol]();
  }
  /**
   * Log a stack trace.
   */
  trace(message, ...args) {
    const con = privateConsole.get(this);
    con.trace(message, ...args);
    this[lastWasBlankSymbol](false);
    return this[incLogCallCountSymbol]();
  }
  /**
   * Log a warning message with symbol.
   */
  warn(...args) {
    return this.#symbolApply("warn", args);
  }
  /**
   * Write to stdout without a newline or indentation.
   */
  write(text) {
    const con = privateConsole.get(this);
    con._stdout.write(text);
    this[lastWasBlankSymbol](false);
    return this;
  }
  /**
   * Show a progress indicator (can be cleared with clearLine).
   * Simple status message without spinner animation.
   */
  progress(text) {
    const con = privateConsole.get(this);
    const stream = this.#getTargetStream();
    const streamObj = stream === "stderr" ? con._stderr : con._stdout;
    streamObj.write(`\u2234 ${text}`);
    this[lastWasBlankSymbol](false);
    return this;
  }
  /**
   * Clear the current line.
   */
  clearLine() {
    const con = privateConsole.get(this);
    const stream = this.#getTargetStream();
    const streamObj = stream === "stderr" ? con._stderr : con._stdout;
    if (streamObj.isTTY) {
      streamObj.cursorTo(0);
      streamObj.clearLine(0);
    } else {
      streamObj.write("\r\x1B[K");
    }
    return this;
  }
}
Object.defineProperties(
  Logger.prototype,
  Object.fromEntries(
    (() => {
      const entries = [
        [
          kGroupIndentationWidthSymbol,
          {
            ...consolePropAttributes,
            value: 2
          }
        ],
        [
          Symbol.toStringTag,
          {
            __proto__: null,
            configurable: true,
            value: "logger"
          }
        ]
      ];
      for (const { 0: key, 1: value } of Object.entries(globalConsole)) {
        if (!Logger.prototype[key] && typeof value === "function") {
          const { [key]: func } = {
            [key](...args) {
              const con = privateConsole.get(this);
              const result = con[key](...args);
              return result === void 0 || result === con ? this : result;
            }
          };
          entries.push([
            key,
            {
              ...consolePropAttributes,
              value: func
            }
          ]);
        }
      }
      return entries;
    })()
  )
);
const logger = new Logger();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  LOG_SYMBOLS,
  Logger,
  incLogCallCountSymbol,
  lastWasBlankSymbol,
  logger
});
//# sourceMappingURL=logger.js.map
