/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { Diagnostic } from "#log/Diagnostic.js";
import { DiagnosticPresentation } from "#log/DiagnosticPresentation.js";
import { DiagnosticSource } from "#log/DiagnosticSource.js";
import { InternalError } from "#MatterError.js";
import { Duration } from "#time/Duration.js";
import "#time/StandardTime.js";
import { Time } from "#time/Time.js";
import { Timestamp } from "#time/Timestamp.js";
import { Boot } from "./Boot.js";
function Lifetime(...name) {
  return Lifetime.process.join(...name);
}
class LifetimeImplementation {
  #name;
  #owner;
  #startedAt;
  #details;
  #spans;
  #closing;
  #isClosed = false;
  constructor(name, owner) {
    this.#name = name.length > 1 ? name : name[0];
    this.#startedAt = Time.nowMs;
    this.#owner = owner;
    if (owner) {
      owner.spans.add(this);
    }
  }
  get spans() {
    if (!this.#spans) {
      this.#spans = /* @__PURE__ */ new Set();
    }
    return this.#spans;
  }
  get name() {
    return this.#name;
  }
  set name(name) {
    this.#name = name;
  }
  get startedAt() {
    return this.#startedAt;
  }
  get details() {
    return this.#details ?? {};
  }
  get owner() {
    return this.#owner;
  }
  set owner(owner) {
    if (!this.#owner) {
      throw new InternalError("Cannot move ownership of root lifetime");
    }
    if (this.#owner === owner) {
      return;
    }
    removeSpan(this.owner, this);
    this.#owner = owner;
    this.#owner?.spans.add(this);
  }
  join(...name) {
    return new LifetimeImplementation(name, this);
  }
  closing() {
    if (!this.#closing) {
      this.#closing = this.join("closing");
      const disposeClosing = this.#closing[Symbol.dispose].bind(this.#closing);
      this.#closing[Symbol.dispose] = () => {
        disposeClosing();
        this[Symbol.dispose]();
      };
    }
    return this.#closing;
  }
  get isOpen() {
    return this.#closing === void 0 && !this.#isClosed;
  }
  get isClosing() {
    return this.#closing !== void 0 || this.#isClosed;
  }
  get isClosed() {
    return this.#isClosed;
  }
  get [DiagnosticPresentation.value]() {
    if (!this.#owner) {
      return Diagnostic.node("\u{1F331}", "Lifetimes", {
        children: this.spans
      });
    }
    const header = [this.#name];
    if (this.isClosed) {
      header.push(Diagnostic.weak("(zombie)"));
    }
    const details = {
      up: Duration.format(Timestamp.delta(this.startedAt, Time.nowMs)),
      ...this.#details
    };
    header.push(Diagnostic.dict(details));
    const result = [header];
    if (this.#spans?.size) {
      result.push(Diagnostic.list(this.spans));
    }
    return result;
  }
  [Symbol.dispose]() {
    if (!this.#owner) {
      return;
    }
    this.#isClosed = true;
    if (this.#spans?.size) {
      return;
    }
    removeSpan(this.#owner, this);
  }
}
let process = new LifetimeImplementation(["process"]);
DiagnosticSource.add(process);
function removeSpan(owner, span) {
  if (!owner) {
    return;
  }
  owner.spans.delete(span);
  if (owner.isClosed && !owner.spans?.size) {
    owner[Symbol.dispose]();
  }
}
((Lifetime2) => {
  function of(subject) {
    return subject?.[Lifetime2.owner] ?? Lifetime2.process;
  }
  Lifetime2.of = of;
  Lifetime2.owner = /* @__PURE__ */ Symbol("owner");
})(Lifetime || (Lifetime = {}));
Object.defineProperties(Lifetime, {
  process: {
    get() {
      return process;
    }
  },
  mock: {
    get() {
      return new LifetimeImplementation(["mock"]);
    }
  }
});
Boot.init(() => {
  process = new LifetimeImplementation(["process"]);
  DiagnosticSource.add(process);
}, "state");
export {
  Lifetime
};
//# sourceMappingURL=Lifetime.js.map
