/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { NodeJsStyleInspectable } from "#log/NodeJsStyleInspectable.js";
import { decamelize } from "#util/identifier-case.js";
import { asError, errorOf } from "./util/Error.js";
const codes = /* @__PURE__ */ new WeakMap();
class MatterError extends Error {
  /**
   * Convert the error to formatted text.
   *
   * matter.js encodes errors with modern JS features including {@link Error#cause} and {@link AggregateError#errors}
   * subfields.  You can use this function to ensure all error details are presented regardless of environment.
   */
  format(format = "plain", indents = 0) {
    let formatterFor = MatterError.formatterFor;
    if (typeof formatterFor !== "function") {
      formatterFor = MatterError.defaultFormatterFactory;
    }
    let formatter = formatterFor(format);
    if (typeof formatter !== "function") {
      formatter = fallbackFormatter;
    }
    let result = formatter(this, indents);
    if (typeof result !== "string") {
      result = `${result}`;
    }
    return result;
  }
  /**
   * A unique textual identifier for the error.
   */
  get id() {
    return MatterError.idFor(this.constructor);
  }
  /**
   * A unique textual identifier for the error.
   */
  static get id() {
    return MatterError.idFor(this);
  }
  /**
   * Obtain matter.js-style error ID for given error constructor.
   */
  static idFor(type) {
    let id = codes.get(type);
    if (id === void 0) {
      let name = type.name;
      if (name.endsWith("Error")) {
        name = name.substring(0, name.length - 5);
      }
      if (name.startsWith("Matter")) {
        name = name.substring(6);
      }
      id = decamelize(name);
      if (id === "") {
        id = "general";
      }
      codes.set(type, id);
    }
    return id;
  }
  /**
   * Rethrow an error unless it is an instance of this class.
   */
  static accept(error) {
    if (error instanceof this) {
      return;
    }
    throw error;
  }
  /**
   * Rethrow an error if it is an instance of this class.
   */
  static reject(error) {
    if (error instanceof this) {
      throw error;
    }
  }
  /**
   * Replace the message in an error.
   *
   * In addition to setting the message, updates the message in the stack.
   */
  static replaceMessage(error, message) {
    const oldMessage = error.message;
    error.message = message;
    const stack = error.stack?.split("\n");
    const messagePos = stack?.findIndex((line) => {
      if (line.startsWith("Error: ")) {
        line = line.slice(7);
      }
      if (line === oldMessage) {
        return true;
      }
    });
    if (messagePos !== void 0 && messagePos !== -1) {
      stack[messagePos] = message;
      error.stack = stack.join("\n");
    }
  }
  /**
   * The fallback formatter factory.  This produces a limited plaintext formatter.
   */
  static defaultFormatterFactory = () => fallbackFormatter;
  /**
   * The error formatter factory.  The default formatter is replaced by Matter.js in ./Format.ts.
   */
  static formatterFor = MatterError.defaultFormatterFactory;
  /**
   * If the causal chain of an error includes an error of type {@link T}, returns the first such error encountered.
   */
  static of(error) {
    if (error instanceof this) {
      return error;
    }
    const e = asError(error);
    if (e.cause) {
      const sre = this.of(e.cause);
      if (sre) {
        return sre;
      }
    }
    if (e instanceof AggregateError && e.errors) {
      for (const e2 of e.errors) {
        const sre = this.of(e2);
        if (sre) {
          return sre;
        }
      }
    }
  }
}
class NoProviderError extends MatterError {
}
class InternalError extends MatterError {
}
class NotImplementedError extends InternalError {
}
class MatterFlowError extends MatterError {
}
class UnexpectedDataError extends MatterError {
}
class ImplementationError extends MatterError {
}
class ImportError extends MatterError {
}
class ReadOnlyError extends ImplementationError {
  constructor(message = "This view is read-only") {
    super(message);
  }
}
class MatterAggregateError extends AggregateError {
  constructor(causes, message) {
    causes = [...causes].map(errorOf);
    super(causes, message);
  }
  /**
   * A unique textual identifier for the error.
   */
  get id() {
    return MatterError.idFor(this.constructor);
  }
  /**
   * A unique textual identifier for the error.
   */
  static get id() {
    return MatterError.idFor(this);
  }
  /**
   * Add causes without stack traces.
   *
   * This is useful to create a compact representation if all child errors originate externally or from the same
   * logical location as the parent error.
   */
  addStackless(error) {
    error.stack = void 0;
    this.errors.push(error);
  }
  /**
   * Wait for all promises to settle and throw an error if any of them reject as MatterAggregateError
   * (or extended class). Promise results are not returned.
   */
  static async allSettled(promises, message = "Errors happened") {
    const results = await Promise.allSettled(promises);
    const errors = results.filter((result) => result.status === "rejected").map((result) => result.reason);
    if (errors.length) {
      throw new this(errors, message);
    }
    return results.map((result) => result.value);
  }
  format = MatterError.prototype.format;
}
function fallbackFormatter(value, indents = 0) {
  if (value === void 0 || value === null) {
    return `${value}`;
  }
  function formatOne(value2, indents2, messagePrefix) {
    const { message, stack, cause, errors } = value2;
    let indent;
    if (typeof indents2 !== "number" || indents2 < 0) {
      indent = "";
    } else {
      indent = "  ".repeat(indents2);
    }
    const buffer = [`${indent}${messagePrefix}${message ?? "(unknown error)"}`];
    if (stack !== void 0 && stack !== null) {
      const frames = stack.toString().split("\n");
      frames.shift();
      buffer.push(...frames.map((f) => `${indent}  ${f.trim()}`));
    }
    if (cause !== void 0) {
      buffer.push(formatOne(cause, indents2, "Caused by: "));
    }
    if (typeof errors?.[Symbol.iterator] === "function") {
      let causeNumber = 0;
      for (const error of errors) {
        buffer.push(formatOne(error, indents2 + 1, `Cause #${causeNumber++}: `));
      }
    }
    return buffer.join("\n");
  }
  return formatOne(value, indents, "");
}
class CanceledError extends MatterError {
  constructor(message = "Operation canceled", options) {
    super(message, options);
  }
}
class TimeoutError extends MatterError {
  constructor(message = "Operation timed out", options) {
    super(message, options);
  }
}
class AbortedError extends CanceledError {
  constructor(message = "Operation aborted", options) {
    super(message, options);
  }
  /**
   * Determine whether a cause signifies abort.
   *
   * We include {@link DOMException} with name "AbortError" which is the standard error thrown if you invoke
   * {@link AbortController#abort} without a cause.
   */
  static is(cause) {
    return cause instanceof AbortedError || cause instanceof DOMException && cause.name === "AbortError";
  }
  /**
   * Accept both {@link AbortedError} and {@link DOMException} with name "AbortError".
   */
  static accept(cause) {
    if (AbortedError.is(cause)) {
      return;
    }
    return super.accept(cause);
  }
}
class ClosedError extends CanceledError {
  constructor(message = "Component closed", options) {
    super(message, options);
  }
}
function inspector(depth, options) {
  const formatterFor = MatterError.formatterFor;
  if (typeof formatterFor !== "function") {
    return this;
  }
  const format = formatterFor(options.colors ? "ansi" : "plain");
  if (typeof format !== "function") {
    return this;
  }
  return format(this, depth);
}
NodeJsStyleInspectable(MatterError.prototype, inspector);
NodeJsStyleInspectable(MatterAggregateError.prototype, inspector);
Object.defineProperty(MatterAggregateError.prototype, "format", {
  value: MatterError.prototype.format,
  configurable: true,
  writable: true,
  enumerable: false
});
export {
  AbortedError,
  CanceledError,
  ClosedError,
  ImplementationError,
  ImportError,
  InternalError,
  MatterAggregateError,
  MatterError,
  MatterFlowError,
  NoProviderError,
  NotImplementedError,
  ReadOnlyError,
  TimeoutError,
  UnexpectedDataError
};
//# sourceMappingURL=MatterError.js.map
