"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 DescriptorServer_exports = {};
__export(DescriptorServer_exports, {
  DescriptorServer: () => DescriptorServer
});
module.exports = __toCommonJS(DescriptorServer_exports);
var import_IndexBehavior = require("#behavior/system/index/IndexBehavior.js");
var import_EndpointLifecycle = require("#endpoint/properties/EndpointLifecycle.js");
var import_general = require("@matter/general");
var import_model = require("@matter/model");
var import_types = require("@matter/types");
var import_DescriptorBehavior = require("./DescriptorBehavior.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("DescriptorServer");
class DescriptorServer extends import_DescriptorBehavior.DescriptorBehavior {
  static dependencies = [import_IndexBehavior.IndexBehavior];
  async initialize() {
    if (this.endpoint.behaviors.has(import_IndexBehavior.IndexBehavior)) {
      this.reactTo(this.agent.get(import_IndexBehavior.IndexBehavior).events.change, this.#updatePartsList);
    } else if (this.endpoint.hasParts) {
      for (const endpoint of this.endpoint.parts) {
        this.#monitorDestruction(endpoint);
      }
    }
    await this.#updatePartsList();
    this.reactTo(this.endpoint.lifecycle.changed, this.#updateDescriptor);
    this.state.serverList = this.#serverList;
    this.state.clientList = this.#clientList;
    const enabledClientClusters = Object.keys(this.endpoint.type.clientClusters ?? {});
    if (enabledClientClusters.length) {
      logger.debug(
        `Enabled client cluster(s) [${enabledClientClusters.join(", ")}] for endpoint ${this.endpoint.id} (device type ${this.endpoint.type.name})`
      );
    }
    this.#initializeDeviceTypeList();
  }
  /** Initialize device type list when it is not already initialized. */
  #initializeDeviceTypeList() {
    if (!this.state.deviceTypeList.length) {
      const partType = this.endpoint.type;
      this.state.deviceTypeList = [
        {
          deviceType: partType.deviceType,
          revision: partType.deviceRevision
        }
      ];
    }
  }
  /**
   * Extend device type metadata.  This is a shortcut for deduped insert into the deviceTypeList cluster attribute.
   *
   * @param deviceTypes an array of objects or named device types as defined in {@link Matter}
   */
  addDeviceTypes(...deviceTypes) {
    this.#initializeDeviceTypeList();
    const list = this.state.deviceTypeList;
    nextInput: for (let newDeviceType of deviceTypes) {
      if (typeof newDeviceType === "string") {
        const dt = import_model.Matter.deviceTypes(newDeviceType);
        if (dt === void 0) {
          throw new import_general.ImplementationError(`Device type ${newDeviceType} not found`);
        }
        newDeviceType = { deviceType: (0, import_types.DeviceTypeId)(dt.id), revision: dt.revision };
      }
      for (const existingDeviceType of list) {
        if ((0, import_general.isDeepEqual)(newDeviceType, existingDeviceType)) {
          continue nextInput;
        }
      }
      list.push(newDeviceType);
    }
  }
  /**
   * Add semantic tags.  This is a shortcut for deduped insert into the tagList cluster attribute.
   *
   * You must enable the "TagList" feature to use this method.
   */
  addTags(...tags) {
    if (!this.features.tagList) {
      throw new import_general.ImplementationError('You must enable the descriptor "TagList" feature to set tags');
    }
    const list = this.state.tagList;
    nextInput: for (const newTag of tags) {
      for (const existingTag of list) {
        if (existingTag.mfgCode === newTag.mfgCode && existingTag.namespaceId === newTag.namespaceId && existingTag.tag === newTag.tag) {
          if (existingTag.label !== newTag.label && newTag.label !== null && newTag.label !== void 0) {
            existingTag.label = newTag.label;
            continue nextInput;
          }
        }
      }
      list.push(newTag);
    }
  }
  /**
   * Check for presence of a device type.
   */
  hasDeviceType(type) {
    return this.state.deviceTypeList.findIndex((dt) => dt.deviceType === type) !== -1;
  }
  /**
   * Process a structure change event and trigger state updates if necessary.
   */
  async #updateDescriptor(type, endpoint) {
    switch (type) {
      case import_EndpointLifecycle.EndpointLifecycle.Change.Ready:
        if (!this.endpoint.parts.has(endpoint)) {
          return;
        }
        await this.#updatePartsList();
        if (!this.endpoint.behaviors.has(import_IndexBehavior.IndexBehavior)) {
          this.#monitorDestruction(endpoint);
        }
        break;
      case import_EndpointLifecycle.EndpointLifecycle.Change.ServersChanged:
        if (endpoint !== this.endpoint) {
          return;
        }
        await this.context.transaction.addResources(this);
        await this.context.transaction.begin();
        this.state.serverList = this.#serverList;
        break;
      /*
                   * No producer fires ClientsChanged today; endpoint.type.clientClusters is static post-construction.
      
                   case EndpointLifecycle.Change.ClientsChanged:
                       if (endpoint !== this.endpoint) {
                           return;
                       }
                       await this.context.transaction.addResources(this);
                       await this.context.transaction.begin();
                       this.state.clientList = this.#clientList;
                       break;
                   */
      case import_EndpointLifecycle.EndpointLifecycle.Change.Destroying:
        if (endpoint !== this.endpoint) {
          return;
        }
        await this.stopReacting({ reactor: this.#updatePartsList });
        break;
    }
  }
  /**
   * Monitor endpoint for removal.
   */
  #monitorDestruction(endpoint) {
    this.reactTo(endpoint.lifecycle.destroyed, this.#updatePartsList);
  }
  /**
   * Update the parts list.
   */
  async #updatePartsList() {
    const endpoint = this.endpoint;
    let numbers;
    if (this.agent.has(import_IndexBehavior.IndexBehavior)) {
      const index = this.agent.get(import_IndexBehavior.IndexBehavior);
      numbers = Object.keys(index.partsByNumber).map((n) => Number.parseInt(n));
      const pos = numbers.indexOf(this.endpoint.number);
      if (pos !== -1) {
        numbers.splice(pos, 1);
      }
    } else if (endpoint.hasParts) {
      numbers = [...endpoint.parts].map((endpoint2) => endpoint2.lifecycle.hasNumber ? endpoint2.number : void 0).filter((n) => n !== void 0);
    } else {
      numbers = [];
    }
    numbers.sort();
    if (this.state.partsList.length === numbers.length) {
      let i = numbers.length;
      for (; i < numbers.length; i++) {
        if (this.state.partsList[i] !== numbers[i]) {
          break;
        }
      }
      if (i === numbers.length) {
        return;
      }
    }
    await this.context.transaction.addResources(this);
    await this.context.transaction.begin();
    this.state.partsList = numbers;
  }
  /**
   * Computed current server list.
   */
  get #serverList() {
    const list = new Array();
    for (const type of Object.values(this.endpoint.behaviors.supported)) {
      const clusterId = type.cluster?.id;
      if (clusterId) {
        list.push(clusterId);
      }
    }
    return list;
  }
  /**
   * Computed current client list from registered client cluster declarations.
   */
  get #clientList() {
    const list = new Array();
    for (const type of Object.values(this.endpoint.type.clientClusters ?? {})) {
      const clusterId = type.cluster?.id;
      if (clusterId) {
        list.push(clusterId);
      }
    }
    return list;
  }
}
//# sourceMappingURL=DescriptorServer.js.map
