"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var Construction_exports = {};
__export(Construction_exports, {
  Construction: () => Construction,
  asyncNew: () => asyncNew
});
module.exports = __toCommonJS(Construction_exports);
var import_DiagnosticPresentation = require("#log/DiagnosticPresentation.js");
var import_LogFormat = require("#log/LogFormat.js");
var import_Logger = require("../log/Logger.js");
var import_MatterError = require("../MatterError.js");
var import_Error = require("./Error.js");
var import_identifier_case = require("./identifier-case.js");
var import_Lifecycle = require("./Lifecycle.js");
var import_Lifetime = require("./Lifetime.js");
var import_Observable = require("./Observable.js");
var import_Promises = require("./Promises.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
async function asyncNew(constructor, ...args) {
  const subject = new constructor(...args);
  if (subject.construction.status === import_Lifecycle.Lifecycle.Status.Inactive) {
    throw new import_MatterError.ImplementationError(
      `You cannot use asyncNew on ${constructor.name} because its construction is controlled by another component`
    );
  }
  await subject.construction.ready;
  return subject;
}
const constructSymbol = /* @__PURE__ */ Symbol("construct");
const destructSymbol = /* @__PURE__ */ Symbol("destruct");
const createConstruction = /* @__PURE__ */ (() => {
  class Construction2 {
    #initializerPromise;
    #awaiterPromise;
    #awaiterResolve;
    #awaiterReject;
    #closedPromise;
    #closedResolve;
    #closedReject;
    #error;
    #errorForDependencies;
    #primaryCauseHandled = false;
    #change;
    #status = import_Lifecycle.Lifecycle.Status.Inactive;
    #lifetime;
    #subject;
    #readyThenable;
    #closedThenable;
    constructor(subject, initializer) {
      this.#subject = subject;
      if (!initializer) {
        assertDeferred(subject);
      }
      if (initializer) {
        this.#invokeInitializer(initializer);
      }
    }
    get [Symbol.toStringTag]() {
      return "Construction";
    }
    get error() {
      return this.#error;
    }
    get status() {
      return this.#status;
    }
    get change() {
      if (this.#change === void 0) {
        this.#change = (0, import_Observable.Observable)();
      }
      return this.#change;
    }
    get isErrorHandled() {
      return this.#primaryCauseHandled;
    }
    join(...name) {
      return this.#activeLifetime().join(...name);
    }
    start(...args) {
      if (this.#status !== import_Lifecycle.Lifecycle.Status.Inactive) {
        throw new import_MatterError.ImplementationError(`Cannot initialize ${this.#subject} because it is already active`);
      }
      assertDeferred(this.#subject);
      this.#applyStatus(import_Lifecycle.Lifecycle.Status.Initializing);
      try {
        const initializeDeferred = () => this.#subject[constructSymbol](...args);
        this.#invokeInitializer(initializeDeferred);
      } catch (e) {
        this.#rejected(e);
        return;
      }
    }
    assert(description, dependency) {
      import_Lifecycle.Lifecycle.assertActive(this.#status, description ?? nameOf(this.#subject));
      if (arguments.length < 2) {
        return;
      }
      try {
        if (dependency === void 0) {
          throw new import_MatterError.ImplementationError(`Property is undefined`);
        }
      } catch (e) {
        let error;
        if (e instanceof Error) {
          error = e;
        } else {
          error = new import_MatterError.ImplementationError(e?.toString() ?? "(unknown error)");
        }
        error.message = `Cannot access ${description}: ${error.message}`;
        throw error;
      }
      return dependency;
    }
    then(onfulfilled, onrejected) {
      const handleRejection = onrejected ? () => onrejected?.(this.#crashedError()) : void 0;
      if (this.#status === import_Lifecycle.Lifecycle.Status.Inactive || this.#status === import_Lifecycle.Lifecycle.Status.Initializing) {
        if (!this.#awaiterPromise) {
          this.#awaiterPromise = new Promise((resolve, reject) => {
            this.#awaiterResolve = resolve;
            this.#awaiterReject = reject;
          });
        }
        return this.#awaiterPromise.then(onfulfilled, handleRejection);
      }
      const promise = this.#error ? Promise.reject(this.#crashedError()) : Promise.resolve(this.#subject);
      return promise.then(onfulfilled, handleRejection);
    }
    catch(onrejected) {
      return this.then(void 0, onrejected);
    }
    onSuccess(actor) {
      const onSuccess = () => {
        const errorHandler = this.#createErrorHandler("onSuccess");
        try {
          const result = actor();
          if (import_Promises.MaybePromise.is(result)) {
            return Promise.resolve(result).catch(errorHandler);
          }
        } catch (e) {
          errorHandler(e);
        }
      };
      this.then(onSuccess).catch((e) => {
        import_Lifecycle.CrashedDependencyError.accept(e);
      });
    }
    onError(actor) {
      const onError = (error) => {
        const errorHandler = this.#createErrorHandler("onError");
        try {
          const result = actor((0, import_Error.errorOf)(error));
          if (import_Promises.MaybePromise.is(result)) {
            return result.then(void 0, errorHandler);
          }
        } catch (e) {
          errorHandler(e);
        }
      };
      this.ready.then(void 0, onError);
    }
    onCompletion(actor) {
      const onCompletion = () => {
        const errorHandler = this.#createErrorHandler("onCompletion");
        try {
          actor();
        } catch (e) {
          errorHandler(e);
        }
      };
      this.then(onCompletion, onCompletion);
    }
    close(destructor) {
      const destructorError = this.#createErrorHandler("destructor");
      const destroyed = () => {
        this.#applyStatus(import_Lifecycle.Lifecycle.Status.Destroyed);
        if (this.#closedResolve) {
          this.#closedResolve();
          this.#closedResolve = this.#closedReject = void 0;
        }
      };
      const destruct = this.#subject[destructSymbol];
      const invokeDestruct = destruct ? () => {
        try {
          const promise = destruct.bind(this.#subject)();
          if (promise) {
            return promise.then(void 0, destructorError).then(destroyed);
          }
        } catch (e) {
          destructorError(e);
        }
        destroyed();
      } : destroyed;
      const invokeDestructor = destructor ? () => {
        try {
          const promise = destructor();
          if (promise) {
            return promise.then(void 0, destructorError).then(invokeDestruct);
          }
        } catch (e) {
          destructorError(e);
        }
        invokeDestruct();
      } : invokeDestruct;
      const beginDestruction = () => {
        if (this.#status === import_Lifecycle.Lifecycle.Status.Destroying || this.#status === import_Lifecycle.Lifecycle.Status.Destroyed) {
          return this.closed;
        }
        this.#applyStatus(import_Lifecycle.Lifecycle.Status.Destroying);
        return invokeDestructor();
      };
      switch (this.#status) {
        case import_Lifecycle.Lifecycle.Status.Initializing:
          return this.then(beginDestruction, beginDestruction);
        case import_Lifecycle.Lifecycle.Status.Destroying:
          return this.closed;
        case import_Lifecycle.Lifecycle.Status.Destroyed:
          return;
        default:
          return beginDestruction();
      }
    }
    finally(onfinally) {
      return Promise.prototype.finally.call(this, onfinally);
    }
    setStatus(newStatus) {
      if (this.#status === newStatus) {
        return;
      }
      switch (this.#status) {
        case newStatus:
          return;
        case import_Lifecycle.Lifecycle.Status.Destroying:
          if (newStatus !== import_Lifecycle.Lifecycle.Status.Destroyed) {
            throw new import_MatterError.ImplementationError("Cannot change status because destruction is ongoing");
          }
          break;
        case import_Lifecycle.Lifecycle.Status.Destroyed:
          throw new import_MatterError.ImplementationError("Cannot change status because destruction is final");
        case import_Lifecycle.Lifecycle.Status.Initializing:
          throw new import_MatterError.ImplementationError("Cannot change status because initialization is ongoing");
      }
      switch (newStatus) {
        case import_Lifecycle.Lifecycle.Status.Inactive:
          this.#awaiterPromise = this.#closedPromise = void 0;
          this.#primaryCauseHandled = false;
          this.#error = this.#errorForDependencies = void 0;
          this.#readyThenable = this.#closedThenable = void 0;
          break;
        case import_Lifecycle.Lifecycle.Status.Active:
          this.#awaiterPromise = this.#closedPromise = void 0;
          this.#error = this.#errorForDependencies = void 0;
          this.#readyThenable = this.#closedThenable = void 0;
          break;
        default:
          break;
      }
      this.#applyStatus(newStatus);
    }
    crash(newError) {
      this.#error = newError;
      this.#applyStatus(import_Lifecycle.Lifecycle.Status.Crashed);
    }
    get ready() {
      if (this.#readyThenable === void 0) {
        this.#readyThenable = {
          [Symbol.toStringTag]: "AsyncConstruction#primary",
          then: (onfulfilled, onrejected) => {
            let rejectionHandler;
            if (onrejected) {
              this.#primaryCauseHandled = true;
              rejectionHandler = () => onrejected((0, import_Error.errorOf)(this.#error));
            }
            return this.then(onfulfilled, rejectionHandler);
          }
        };
      }
      return this.#readyThenable;
    }
    get closed() {
      if (this.#closedPromise === void 0) {
        this.#closedPromise = new Promise((resolve, reject) => {
          this.#closedResolve = resolve;
          this.#closedReject = reject;
        });
      }
      if (this.#closedThenable === void 0) {
        this.#closedThenable = {
          [Symbol.toStringTag]: "AsyncConstruction#primary",
          then: (onfulfilled, onrejected) => {
            let rejectionHandler;
            if (onrejected) {
              this.#primaryCauseHandled = true;
              rejectionHandler = () => onrejected((0, import_Error.errorOf)(this.#error));
            }
            return this.#closedPromise.then(onfulfilled, rejectionHandler);
          }
        };
      }
      return this.#closedThenable;
    }
    toString() {
      return `Construction(${nameOf(this.#subject)})`;
    }
    #invokeInitializer(initializer) {
      this.#applyStatus(import_Lifecycle.Lifecycle.Status.Initializing);
      this.#initializerPromise = initializer();
      if (import_Promises.MaybePromise.is(this.#initializerPromise)) {
        this.#initializerPromise.then(
          () => this.#resolved(),
          (e) => this.#rejected(e)
        );
      } else {
        this.#resolved();
      }
    }
    #crashedError() {
      if (!this.#primaryCauseHandled && this.#error) {
        this.#primaryCauseHandled = true;
        return this.#error;
      }
      if (this.#errorForDependencies) {
        return this.#errorForDependencies;
      }
      this.#errorForDependencies = new import_Lifecycle.CrashedDependencyError(
        nameOf(this.#subject),
        "unavailable due to initialization error"
      );
      this.#errorForDependencies.subject = this.#subject;
      this.#errorForDependencies.cause = this.#error;
      return this.#errorForDependencies;
    }
    #applyStatus(newStatus) {
      if (this.#status === newStatus) {
        return;
      }
      this.#status = newStatus;
      switch (this.#status) {
        case import_Lifecycle.Lifecycle.Status.Initializing:
        case import_Lifecycle.Lifecycle.Status.Active:
        case import_Lifecycle.Lifecycle.Status.Destroying:
          if (!this.#lifetime) {
            this.#lifetime = this.#joinOwner();
          }
          if (this.#status === import_Lifecycle.Lifecycle.Status.Destroying) {
            this.#lifetime.closing();
          }
          break;
        default:
          if (this.#lifetime) {
            this.#lifetime.closing()[Symbol.dispose]();
            this.#lifetime[Symbol.dispose]();
            this.#lifetime = void 0;
          }
          break;
      }
      if (this.#change) {
        this.#change.emit(this.#status, this.#subject);
      }
    }
    #resolved() {
      if (this.#status === import_Lifecycle.Lifecycle.Status.Initializing) {
        this.#applyStatus(import_Lifecycle.Lifecycle.Status.Active);
      }
      if (this.#awaiterResolve) {
        const resolve = this.#awaiterResolve;
        this.#awaiterResolve = this.#awaiterReject = void 0;
        resolve(this.#subject);
      }
    }
    #rejected(cause) {
      if (this.#status !== import_Lifecycle.Lifecycle.Status.Destroying && this.#status !== import_Lifecycle.Lifecycle.Status.Destroyed) {
        this.#error = cause;
        this.#applyStatus(import_Lifecycle.Lifecycle.Status.Crashed);
      }
      if (this.#awaiterReject) {
        const reject = this.#awaiterReject;
        this.#awaiterResolve = this.#awaiterReject = void 0;
        reject(this.#crashedError());
      }
      if (this.#closedReject) {
        this.#primaryCauseHandled = true;
        const reject = this.#closedReject;
        this.#closedResolve = this.#closedReject = void 0;
        reject(cause);
      }
      if (!this.#primaryCauseHandled) {
        this.#unhandledError(cause);
      }
    }
    #unhandledError(...args) {
      const logger = import_Logger.Logger.get(this.#subject.constructor.name);
      logger.error(...args);
    }
    #createErrorHandler(name) {
      return (e) => {
        this.#unhandledError(`Unhandled error in ${nameOf(this.#subject)} ${name}:`, e);
      };
    }
    #activeLifetime() {
      if (this.#lifetime) {
        if (this.#status === import_Lifecycle.Lifecycle.Status.Destroying) {
          return this.#lifetime.closing();
        }
        return this.#lifetime;
      }
      const zombie = this.#joinOwner();
      zombie[Symbol.dispose]();
      return zombie;
    }
    #joinOwner() {
      const lifetime = import_Lifetime.Lifetime.of(this.#subject);
      return lifetime.join((0, import_identifier_case.decamelize)(nameOf(this.#subject), " "));
    }
  }
  return (subject, initializer) => new Construction2(subject, initializer);
})();
function Construction(subject, initializer) {
  return createConstruction(subject, initializer);
}
((Construction2) => {
  function all(subjects, onError) {
    if (onError === void 0) {
      onError = (errors) => new import_Lifecycle.CrashedDependenciesError(errors);
    }
    const subjectArray = [...subjects];
    const uninitialized = subjectArray.filter(
      (subject) => subject.construction.status === import_Lifecycle.Lifecycle.Status.Initializing
    );
    if (uninitialized.length) {
      return Promise.allSettled(uninitialized.map((backing) => backing.construction)).then(
        () => (
          // Recurse to ensure subjects added subsequent to initial "all" settle
          all(subjects, onError)
        )
      );
    }
    const crashed = Object.values(subjectArray).filter(
      (subject) => subject.construction.status === import_Lifecycle.Lifecycle.Status.Crashed
    );
    if (crashed.length) {
      let error;
      try {
        error = onError(crashed);
      } catch (e) {
        error = (0, import_Error.asError)(e);
      }
      if (error) {
        return Promise.reject(error);
      }
    }
  }
  Construction2.all = all;
  Construction2.construct = constructSymbol;
  Construction2.destruct = destructSymbol;
})(Construction || (Construction = {}));
function assertDeferred(subject) {
  if (typeof subject?.[constructSymbol] !== "function") {
    throw new import_MatterError.ImplementationError(`No initializer defined for ${subject}`);
  }
}
function nameOf(subject) {
  if (import_DiagnosticPresentation.DiagnosticPresentation.name in subject) {
    const name = subject[import_DiagnosticPresentation.DiagnosticPresentation.name];
    if (name !== void 0) {
      return (0, import_LogFormat.LogFormat)("plain")(name);
    }
  }
  if (subject.toString === Object.prototype.toString) {
    return subject.constructor.name;
  }
  return subject.toString();
}
//# sourceMappingURL=Construction.js.map
