"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 NetworkClient_exports = {};
__export(NetworkClient_exports, {
  NetworkClient: () => NetworkClient
});
module.exports = __toCommonJS(NetworkClient_exports);
var import_RemoteDescriptor = require("#behavior/system/commissioning/RemoteDescriptor.js");
var import_ClientNodePhysicalProperties = require("#node/client/ClientNodePhysicalProperties.js");
var import_Node = require("#node/Node.js");
var import_ClientCacheBuffer = require("#storage/client/ClientCacheBuffer.js");
var import_general = require("@matter/general");
var import_model = require("@matter/model");
var import_protocol = require("@matter/protocol");
var import_types = require("@matter/types");
var import_NetworkBehavior = require("./NetworkBehavior.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
class NetworkClient extends import_NetworkBehavior.NetworkBehavior {
  initialize() {
    if (this.#node.nodeType === "group") {
      this.state.autoSubscribe = false;
      this.state.defaultSubscription = void 0;
    } else {
      this.reactTo(this.events.autoSubscribe$Changed, this.#syncAutoSubscribe, { offline: true });
      this.reactTo(this.events.defaultSubscription$Changed, this.#handleDefaultSubscriptionChange, {
        offline: true
      });
      this.reactTo(this.events.subscriptionStatusChanged, this.#flushCacheOnSubscribed);
    }
  }
  async startup() {
    const peerAddress = this.#node.state.commissioning.peerAddress;
    if (peerAddress !== void 0) {
      const peerSet = this.env.get(import_protocol.PeerSet);
      if (!peerSet.has(peerAddress)) {
        const ipAddresses = this.#node.state.commissioning.addresses?.filter((a) => import_general.ServerAddress.isIp(a)) ?? [];
        if (ipAddresses.length) {
          const operationalAddress = import_protocol.OperationalAddress.from((0, import_general.ServerAddress)(ipAddresses[0]));
          if (operationalAddress !== void 0) {
            const persistedParams = this.#node.state.commissioning.sessionParameters;
            peerSet.addKnownPeer({
              address: peerAddress,
              operationalAddress,
              discoveryData: import_RemoteDescriptor.RemoteDescriptor.fromLongForm(this.#node.state.commissioning),
              sessionParameters: persistedParams ? (0, import_protocol.SessionParameters)(persistedParams) : void 0
            });
          }
        }
      }
      const peer = peerSet.get(peerAddress);
      if (peer) {
        peer.protocol = this.#node.protocol;
        peer.physicalProperties = (0, import_ClientNodePhysicalProperties.ClientNodePhysicalProperties)(this.#node);
        const pref = this.state.transportPreference ?? this.#node.owner?.state?.network?.transportPreference;
        peer.transportPreference = pref === "tcp" ? import_general.ChannelType.TCP : void 0;
      }
    }
    await this.#syncAutoSubscribe();
    this.internal.runtime.isReady = true;
  }
  async #handleDefaultSubscriptionChange() {
    await this.#syncAutoSubscribe(false);
    if (this.state.autoSubscribe && !this.state.isDisabled) {
      await this.#syncAutoSubscribe(true);
    }
  }
  async #syncAutoSubscribe(desiredState = this.state.autoSubscribe) {
    if (!this.internal.runtime) {
      return;
    }
    const { isDisabled } = this.state;
    const subscriptionDesired = desiredState && !isDisabled;
    const isNewlyCommissioned = this.internal.isNewlyCommissioned;
    if (isNewlyCommissioned) {
      this.internal.isNewlyCommissioned = false;
    }
    if (subscriptionDesired === !!this.internal.activeSubscription) {
      return;
    }
    if (subscriptionDesired) {
      const subscribe = (0, import_protocol.Subscribe)({
        fabricFilter: true,
        keepSubscriptions: false,
        attributes: [{}],
        events: [{ isUrgent: true }],
        ...this.state.defaultSubscription
      });
      let bootstrapWithRead;
      if (isNewlyCommissioned) {
        for await (const _chunk of this.#node.interaction.read(subscribe)) ;
        bootstrapWithRead = false;
      } else {
        bootstrapWithRead = true;
      }
      this.internal.activeSubscription = await this.#node.interaction.subscribe({
        ...subscribe,
        sustain: true,
        eventFilters: [{ eventMin: this.state.maxEventNumber + 1n }],
        bootstrapWithRead,
        updated: async (update) => {
          for await (const _chunk of update) ;
          if (this.internal.activeSubscription?.subscriptionId !== import_protocol.ClientSubscription.NO_SUBSCRIPTION) {
            this.events.subscriptionAlive.emit();
          }
        },
        closed: () => {
          if (!(this.internal.activeSubscription instanceof import_protocol.SustainedSubscription)) {
            this.events.subscriptionStatusChanged.emit(false);
          }
          this.internal.activeSubscription = void 0;
        }
      });
      if (this.internal.activeSubscription instanceof import_protocol.SustainedSubscription) {
        this.internal.activeSubscription.active.on(
          (isActive) => this.events.subscriptionStatusChanged.emit(isActive)
        );
      } else {
        this.events.subscriptionStatusChanged.emit(true);
      }
    } else {
      this.internal.activeSubscription?.close();
      this.internal.activeSubscription = void 0;
    }
  }
  /**
   * Returns if we actually have an active and established subscription
   * When a Sustained subscription is used we return the active value, otherwise we know when the subscription instance
   * is set.
   */
  get subscriptionActive() {
    const activeSubscription = this.internal.activeSubscription;
    if (activeSubscription === void 0) {
      return false;
    }
    return activeSubscription instanceof import_protocol.SustainedSubscription ? activeSubscription.active.value : true;
  }
  async [Symbol.asyncDispose]() {
    this.internal.activeSubscription?.close();
    this.internal.activeSubscription = void 0;
  }
  #flushCacheOnSubscribed(isActive) {
    if (isActive) {
      const parentEnv = this.#node.owner.env;
      if (parentEnv.has(import_ClientCacheBuffer.ClientCacheBuffer)) {
        parentEnv.get(import_ClientCacheBuffer.ClientCacheBuffer).initiateFlush();
      }
    }
  }
  get #node() {
    return this.env.get(import_Node.Node);
  }
  /**
   * Define logical schema for fields that should persist.
   */
  static schema = new import_model.DatatypeModel({
    name: "NetworkState",
    type: "struct",
    children: [
      (0, import_model.FieldElement)({
        name: "defaultSubscription",
        type: "any",
        default: { type: "properties", properties: {} },
        conformance: "O",
        quality: "N"
      }),
      (0, import_model.FieldElement)({
        name: "isDisabled",
        type: "bool",
        quality: "N",
        default: false
      }),
      (0, import_model.FieldElement)({
        name: "autoSubscribe",
        type: "bool",
        quality: "N",
        default: false
      }),
      (0, import_model.FieldElement)({
        name: "maxEventNumber",
        type: "event-no",
        quality: "N",
        default: (0, import_types.EventNumber)(0)
      }),
      (0, import_model.FieldElement)({
        name: "transportPreference",
        type: "string",
        conformance: "O",
        quality: "N"
      })
    ]
  });
}
((NetworkClient2) => {
  class Internal extends import_NetworkBehavior.NetworkBehavior.Internal {
    /**
     * The active default subscription.
     */
    activeSubscription;
    /**
     * Indicates the node is newly commissioned.
     *
     * When newly commissioned, if automatic subscription is enabled we perform a read before returning from
     * {@link NetworkClient#startup}.  This ensures we have a complete snapshot of the node's state when
     * commissioning logic is complete.
     */
    isNewlyCommissioned = false;
  }
  NetworkClient2.Internal = Internal;
  class State extends import_NetworkBehavior.NetworkBehavior.State {
    /**
     * This subscription defines the default set of attributes and events to which the node will automatically
     * subscribe when started, if autoSubscribe is true. Alternatively, also just Subscribe.Options can be provided
     * to adjust chosen default subscription parameters (see below).
     *
     * The default subscription is a wildcard for all attributes of the node.  You can set to undefined or filter
     * the fields and values but only values selected by this subscription will update automatically.
     *
     * The default subscription updates automatically if you change this property.
     */
    defaultSubscription;
    /**
     * Represents the current operational network state of the node. When true the node is enabled and operational.
     * When false the node is disabled and not operational.
     *
     * This state can be changed at any time to enable or disable the node.
     */
    isDisabled = false;
    /**
     * If true, automatically subscribe to the provided default subscription (or all attributes and events) when
     * the node is started. If false, do not automatically subscribe.
     *
     * The subscription will activate or deactivate automatically if you change this property.
     *
     * Newly commissioned nodes default to true.
     */
    autoSubscribe = false;
    /**
     * The highest event number seen from this node for the default read/subscription.
     */
    maxEventNumber = (0, import_types.EventNumber)(0);
    /**
     * Per-peer transport preference override.
     * If not set, inherits from NetworkServer.transportPreference.
     */
    transportPreference;
  }
  NetworkClient2.State = State;
  class Events extends import_NetworkBehavior.NetworkBehavior.Events {
    autoSubscribe$Changed = new import_general.Observable();
    defaultSubscription$Changed = new import_general.Observable();
    subscriptionStatusChanged = new import_general.Observable();
    subscriptionAlive = new import_general.Observable();
  }
  NetworkClient2.Events = Events;
})(NetworkClient || (NetworkClient = {}));
//# sourceMappingURL=NetworkClient.js.map
