"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 DeviceAdvertiser_exports = {};
__export(DeviceAdvertiser_exports, {
  DeviceAdvertiser: () => DeviceAdvertiser
});
module.exports = __toCommonJS(DeviceAdvertiser_exports);
var import_Advertisement = require("#advertisement/Advertisement.js");
var import_ServiceDescription = require("#advertisement/ServiceDescription.js");
var import_FabricManager = require("#fabric/FabricManager.js");
var import_SessionManager = require("#session/SessionManager.js");
var import_general = require("@matter/general");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("DeviceAdvertiser");
class DeviceAdvertiser {
  #context;
  #advertisers = /* @__PURE__ */ new Set();
  #observers = new import_general.ObserverGroup();
  #isOperational = false;
  #isClosing = false;
  #commissioningService;
  constructor(context) {
    this.#context = context;
    const { fabrics, sessions } = this.#context;
    this.#observers.on(fabrics.events.added, (fabric) => {
      if (!this.#isOperational) {
        return;
      }
      this.#advertiseFabric(fabric, "startup");
    });
    this.#observers.on(fabrics.events.replaced, async (fabric) => {
      if (!this.#isOperational) {
        return;
      }
      const fabricIndexAdvertisements = this.#advertisements(
        (ad) => ad.isOperational() && ad.description.fabric.fabricIndex === fabric.fabricIndex
      );
      if (fabricIndexAdvertisements.every(
        (ad) => ad.isOperational() && ad.description.fabric.globalId === fabric.globalId && ad.description.fabric.nodeId === fabric.nodeId
      )) {
        return;
      }
      for (const ad of fabricIndexAdvertisements) {
        await ad.close();
      }
      this.#advertiseFabric(fabric, "startup");
    });
    this.#observers.on(fabrics.events.deleting, (fabric) => {
      import_Advertisement.Advertisement.cancelAll(this.#advertisements((ad) => ad.isOperational() && ad.description.fabric === fabric));
    });
    this.#observers.on(sessions.sessions.added, (session) => {
      const fabricIndex = session.fabric?.fabricIndex;
      const fabric = fabricIndex ? fabrics.maybeFor(fabricIndex) : void 0;
      if (!fabric) {
        return;
      }
      for (const advertiser of this.#advertisers) {
        const ad = advertiser.advertisementForFabric(fabric);
        if (ad) {
          ad.serviceConnected();
        }
      }
    });
    this.#observers.on(sessions.sessions.deleted, (session) => {
      const fabricIndex = session.fabric?.fabricIndex;
      const fabric = fabricIndex ? fabrics.maybeFor(fabricIndex) : void 0;
      if (fabric) {
        if (fabric.hasSessionForPeer(session.peerNodeId)) {
          return;
        }
        for (const advertiser of this.#advertisers) {
          const ad = advertiser.advertisementForFabric(fabric);
          if (ad) {
            ad.serviceDisconnected();
          }
        }
        return;
      }
      if (!session.isPase) {
        return;
      }
      this.#startCommissioningAdvertisement();
    });
    this.#observers.on(sessions.retry, (session) => {
      if (!session.isSecure || !session.fabric) {
        return;
      }
      this.#advertiseFabric(session.associatedFabric, "retransmit");
    });
    this.#observers.on(this.#context.sessions.subscriptionsChanged, (session, subscription) => {
      if (this.#isOperational && subscription.isCanceledByPeer && session.fabric !== void 0) {
        logger.debug(`Subscription canceled by peer, re-announce`);
        this.#advertiseFabric(session.fabric, "reconnect");
      }
    });
  }
  toString() {
    return "DeviceAdvertiser";
  }
  static [import_general.Environmental.create](env) {
    const instance = new DeviceAdvertiser({
      fabrics: env.get(import_FabricManager.FabricManager),
      sessions: env.get(import_SessionManager.SessionManager)
    });
    env.set(DeviceAdvertiser, instance);
    return instance;
  }
  /**
   * Advertise the device as commissionable.
   */
  enterCommissioningMode(description) {
    this.#commissioningService = description;
    this.#startCommissioningAdvertisement();
  }
  /**
   * Begin automatic broadcast for commissioning if in commissionable mode.
   */
  #startCommissioningAdvertisement() {
    if (this.#isClosing) {
      return;
    }
    if (this.#commissioningService === void 0) {
      return;
    }
    for (const advertiser of this.#advertisers) {
      advertiser.advertise(this.#commissioningService, "startup");
    }
  }
  /**
   * Cease advertising the device as commissionable.
   */
  exitCommissioningMode() {
    if (!this.#commissioningService) {
      return;
    }
    this.#commissioningService = void 0;
    return import_Advertisement.Advertisement.closeAll(this.#advertisements((ad) => ad.isCommissioning()));
  }
  /**
   * Advertise the device as operational.
   */
  enterOperationalMode() {
    if (this.#isOperational || this.#isClosing) {
      return;
    }
    this.#isOperational = true;
    this.#startOperationalAdvertisement();
  }
  /**
   * Begin automatic broadcast for fabrics if in operational mode.
   */
  #startOperationalAdvertisement() {
    if (!this.#isOperational || this.#isClosing) {
      return;
    }
    const fabricsAdvertised = new Set(
      this.#advertisements((ad) => ad.isOperational()).map(
        (ad) => ad.description.fabric
      )
    );
    for (const fabric of this.#context.fabrics) {
      if (!fabricsAdvertised.has(fabric)) {
        this.#advertiseFabric(fabric, "startup");
      }
    }
  }
  /**
   * Cease advertising the device as operational.
   */
  exitOperationalMode() {
    if (!this.#isOperational) {
      return;
    }
    this.#isOperational = false;
    import_Advertisement.Advertisement.cancelAll(this.#advertisements((ad) => ad.isOperational()));
  }
  /**
   * Reset automatic advertisement.
   *
   * This is useful when there is a network change.
   */
  restartAdvertisement() {
    this.#startCommissioningAdvertisement();
    this.#startOperationalAdvertisement();
  }
  async close() {
    this.#isClosing = true;
    this.#observers.close();
    await this.clearAdvertisers();
  }
  hasAdvertiser(advertiser) {
    return this.#advertisers.has(advertiser);
  }
  addAdvertiser(advertiser) {
    this.#advertisers.add(advertiser);
  }
  async deleteAdvertiser(advertiser) {
    this.#advertisers.delete(advertiser);
    await advertiser.close();
  }
  async clearAdvertisers() {
    const advertisers = [...this.#advertisers];
    this.#advertisers.clear();
    await import_general.MatterAggregateError.allSettled(advertisers.map((advertiser) => advertiser.close()));
  }
  #advertiseFabric(fabric, event) {
    if (this.#isClosing) {
      return;
    }
    for (const advertiser of this.#advertisers) {
      if (event === "startup") {
        if (this.#context.sessions.forFabric(fabric).some((session) => session.subscriptions.size > 0)) {
          event = "retransmit";
        }
      }
      advertiser.advertise(import_ServiceDescription.ServiceDescription.Operational({ fabric }), event);
    }
  }
  #advertisements(predicate) {
    return [...this.#advertisers].flatMap(
      (advertiser) => predicate ? advertiser.filter(predicate) : [...advertiser.advertisements]
    );
  }
}
//# sourceMappingURL=DeviceAdvertiser.js.map
