"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 ClientNode_exports = {};
__export(ClientNode_exports, {
  ClientNode: () => ClientNode
});
module.exports = __toCommonJS(ClientNode_exports);
var import_CommissioningClient = require("#behavior/system/commissioning/CommissioningClient.js");
var import_ClientNetworkRuntime = require("#behavior/system/network/ClientNetworkRuntime.js");
var import_NetworkClient = require("#behavior/system/network/NetworkClient.js");
var import_ClientNodeEndpoints = require("#endpoint/properties/ClientNodeEndpoints.js");
var import_EndpointInitializer = require("#endpoint/properties/EndpointInitializer.js");
var import_EndpointLifecycle = require("#endpoint/properties/EndpointLifecycle.js");
var import_EndpointType = require("#endpoint/type/EndpointType.js");
var import_MutableEndpoint = require("#endpoint/type/MutableEndpoint.js");
var import_ClientCacheBuffer = require("#storage/client/ClientCacheBuffer.js");
var import_ClientNodeStore = require("#storage/client/ClientNodeStore.js");
var import_RemoteWriter = require("#storage/client/RemoteWriter.js");
var import_ServerNodeStore = require("#storage/server/ServerNodeStore.js");
var import_general = require("@matter/general");
var import_model = require("@matter/model");
var import_protocol = require("@matter/protocol");
var import_ClientEndpointInitializer = require("./client/ClientEndpointInitializer.js");
var import_ClientNodeInteraction = require("./client/ClientNodeInteraction.js");
var import_Node = require("./Node.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("ClientNode");
class ClientNode extends import_Node.Node {
  #matter;
  #interaction;
  #blockInteractions = false;
  #cachedPeerAddress;
  constructor(options) {
    const opts = {
      ...options,
      number: 0,
      // Create an unfrozen type so we can set the revision when we see the descriptor
      type: (0, import_MutableEndpoint.MutableEndpoint)(ClientNode.RootEndpoint)
    };
    super(opts);
    this.env.close(import_protocol.OccurrenceManager);
    this.env.set(import_Node.Node, this);
    this.env.set(ClientNode, this);
    this.#matter = options.matter ?? import_model.Matter;
  }
  nodeType = "client";
  /**
   * Model of Matter semantics understood by this node.
   *
   * Matter elements missing from this model will not support all functionality.
   */
  get matter() {
    return this.#matter;
  }
  get endpoints() {
    return new import_ClientNodeEndpoints.ClientNodeEndpoints(this);
  }
  get store() {
    return this.env.get(import_ServerNodeStore.ServerNodeStore).clientStores.storeForNode(this);
  }
  // This needs to be sync to ensure a sync initialization
  initialize() {
    const store = this.store;
    this.env.set(import_ClientNodeStore.ClientNodeStore, store);
    const initializer = new import_ClientEndpointInitializer.ClientEndpointInitializer(this);
    this.env.set(import_EndpointInitializer.EndpointInitializer, initializer);
    store.write = (0, import_RemoteWriter.RemoteWriter)(this, initializer.structure);
    import_ClientCacheBuffer.ClientCacheBuffer.configure(this, store);
    initializer.structure.loadCache(store.endpointStores);
    const promise = super.initialize();
    if (store.isPreexisting && promise !== void 0) {
      throw new import_general.InternalError("Unsupported async initialization detected when loading known peer");
    }
    return promise;
  }
  get owner() {
    const owner = super.owner;
    if (owner === void 0) {
      throw new import_general.InternalError("Client node is missing owner");
    }
    return super.owner;
  }
  set owner(owner) {
    super.owner = owner;
  }
  /**
   * Add this node to a fabric.
   */
  async commission(options) {
    await this.act("commission", (agent) => agent.commissioning.commission(options));
  }
  /**
   * Remove this node from the fabric (if commissioned) and locally.
   * This method tries to communicate with the device to decommission it properly and will fail if the device is
   * unreachable.
   * If you cannot reach the device, use {@link delete} instead.
   */
  async decommission() {
    this.lifecycle.change(import_EndpointLifecycle.EndpointLifecycle.Change.Destroying);
    if (this.lifecycle.isCommissioned) {
      this.statusUpdate("decommissioning");
      await this.act("decommission", (agent) => agent.commissioning.decommission());
    }
    await this.delete();
  }
  /**
   * Force-remove the node without first decommissioning.
   *
   * If the node is still available, you should use {@link decommission} to remove it properly from the fabric and only use
   * this method as fallback.  You should inform the user that manual factory-reset may be necessary.
   */
  async delete() {
    const address = this.peerAddress;
    await super.delete();
    if (address) {
      await this.env.maybeGet(import_protocol.PeerSet)?.get(address)?.delete();
    }
  }
  async erase() {
    await this.lifecycle.mutex.produce(this.eraseWithMutex.bind(this));
  }
  /**
   * Disable the node.
   *
   * This shuts down any active connections and prevents future connections until re-enabled.
   */
  async disable() {
    if (this.state.network.isDisabled) {
      return;
    }
    await this.lifecycle.mutex.produce(async () => {
      await this.cancelWithMutex();
      await this.setStateOf(import_NetworkClient.NetworkClient, { isDisabled: true });
    });
  }
  /**
   * Enable the node.
   *
   * If the node is disabled but reachable, this brings it online.
   */
  async enable() {
    if (!this.state.network.isDisabled) {
      return;
    }
    await this.setStateOf(import_NetworkClient.NetworkClient, { isDisabled: false });
    await this.start();
  }
  async eraseWithMutex() {
    await this.cancelWithMutex();
    await super.resetWithMutex();
    this.#cachedPeerAddress = void 0;
    await this.env.get(import_EndpointInitializer.EndpointInitializer).eraseDescendant(this);
  }
  async resetWithMutex() {
    this.#cachedPeerAddress = void 0;
    await super.resetWithMutex();
  }
  createRuntime() {
    return new import_ClientNetworkRuntime.ClientNetworkRuntime(this);
  }
  async prepareRuntimeShutdown() {
  }
  async cancelWithMutex() {
    this.#blockInteractions = true;
    try {
      const interaction = this.#interaction;
      this.#interaction = void 0;
      await interaction?.close();
      await super.cancelWithMutex();
    } finally {
      this.#blockInteractions = false;
    }
  }
  get container() {
    return this.owner?.peers;
  }
  act(actorOrPurpose, actor) {
    if (this.construction.status === import_general.Lifecycle.Status.Inactive) {
      this.construction.start();
    }
    if (this.construction.status === import_general.Lifecycle.Status.Initializing) {
      return this.construction.then(() => super.act(actorOrPurpose, actor));
    }
    return super.act(actorOrPurpose, actor);
  }
  get interaction() {
    if (this.#interaction === void 0) {
      if (this.#blockInteractions) {
        throw new import_general.ImplementationError("Cannot access interaction of a shutting-down node");
      }
      this.#interaction = new import_ClientNodeInteraction.ClientNodeInteraction(this);
    }
    return this.#interaction;
  }
  get peerAddress() {
    const state = this.behaviors.maybeStateOf("commissioning");
    if (state !== void 0) {
      const live = (0, import_protocol.PeerAddress)(state.peerAddress);
      this.#cachedPeerAddress = live;
      return live;
    }
    if (this.#cachedPeerAddress !== void 0) {
      return this.#cachedPeerAddress;
    }
    try {
      const stored = (0, import_protocol.PeerAddress)(this.store.storeForEndpoint(this).peerAddress);
      if (stored !== void 0) {
        this.#cachedPeerAddress = stored;
        return stored;
      }
    } catch (error) {
      import_general.DependencyLifecycleError.accept(error);
      logger.info("Cannot resolve peer address from storage:", error);
    }
    return void 0;
  }
  get identity() {
    const peerAddress = this.peerAddress;
    if (peerAddress) {
      return (0, import_protocol.PeerAddress)(peerAddress).toString();
    }
    return super.identity;
  }
  statusUpdate(message) {
    logger.info(import_general.Diagnostic.strong(this.toString()), message);
  }
}
((ClientNode2) => {
  ClientNode2.RootEndpoint = (0, import_MutableEndpoint.MutableEndpoint)({
    ...import_Node.Node.CommonRootEndpoint,
    deviceRevision: import_EndpointType.EndpointType.UNKNOWN_DEVICE_REVISION
  }).with(import_CommissioningClient.CommissioningClient, import_NetworkClient.NetworkClient);
})(ClientNode || (ClientNode = {}));
Object.freeze(ClientNode.RootEndpoint);
//# sourceMappingURL=ClientNode.js.map
