"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 Endpoint_exports = {};
__export(Endpoint_exports, {
  Endpoint: () => Endpoint
});
module.exports = __toCommonJS(Endpoint_exports);
var import_AttributeClient = require("#cluster/client/AttributeClient.js");
var import_general = require("@matter/general");
var import_types = require("@matter/types");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
class Endpoint {
  /**
   * Create a new Endpoint instance.
   *
   * @param endpoint The ClientEndpoint this Endpoint represents
   * @param deviceTypes One or multiple DeviceTypeDefinitions of the endpoint
   * @param options Options for the endpoint
   */
  constructor(endpoint, deviceTypes, options = {}) {
    this.deviceTypes = deviceTypes;
    this.#endpoint = endpoint;
    this.setDeviceTypes(deviceTypes);
    if (options.endpointId !== void 0) {
      this.number = options.endpointId;
    }
    if (options.uniqueStorageKey !== void 0) {
      this.uniqueStorageKey = options.uniqueStorageKey;
    }
  }
  clusterClients = /* @__PURE__ */ new Map();
  childEndpoints = /* @__PURE__ */ new Map();
  number;
  uniqueStorageKey;
  name = "";
  structureChangedCallback = () => {
  };
  #endpoint;
  /**
   * Access to cached cluster state values using endpoint.state.clusterNameOrId.attributeNameOrId
   * Returns immutable cached attribute values from cluster clients
   */
  get state() {
    return this.#endpoint.state;
  }
  /**
   * Access to cluster commands using endpoint.commands.clusterNameOrId.commandName
   * Returns async functions that can be called to invoke commands on cluster clients
   */
  get commands() {
    return this.#endpoint.commands;
  }
  /**
   * Access to typed cached cluster state values
   * Returns immutable cached attribute values from cluster clients
   */
  stateOf(type) {
    return this.#endpoint.stateOf(type);
  }
  maybeStateOf(type) {
    return this.#endpoint.maybeStateOf(type);
  }
  setStateOf(type, values) {
    return this.#endpoint.setStateOf(type, values);
  }
  /**
   * Access to typed cluster commands
   * Returns async functions that can be called to invoke commands on cluster clients
   */
  commandsOf(type) {
    return this.#endpoint.commandsOf(type);
  }
  get behaviors() {
    return this.#endpoint.behaviors;
  }
  get endpoint() {
    return this.#endpoint;
  }
  /** Get all child endpoints aka parts */
  get parts() {
    return this.childEndpoints;
  }
  get deviceType() {
    return this.deviceTypes[0].code;
  }
  setStructureChangedCallback(callback) {
    this.structureChangedCallback = callback;
    for (const endpoint of this.childEndpoints.values()) {
      endpoint.setStructureChangedCallback(callback);
    }
  }
  removeFromStructure() {
    this.structureChangedCallback = () => {
    };
    for (const endpoint of this.childEndpoints.values()) {
      endpoint.removeFromStructure();
    }
  }
  close() {
  }
  getNumber() {
    if (this.number === void 0) {
      throw new import_general.InternalError("Endpoint has not been assigned yet");
    }
    return this.number;
  }
  addClusterClient(cluster) {
    this.clusterClients.set(cluster.id, cluster);
  }
  getClusterClient(cluster) {
    return this.clusterClients.get(cluster.id);
  }
  getClusterClientById(clusterId) {
    return this.clusterClients.get(clusterId);
  }
  hasClusterClient(cluster) {
    return this.clusterClients.has(cluster.id);
  }
  getDeviceTypes() {
    return this.deviceTypes;
  }
  setDeviceTypes(deviceTypes) {
    const deviceTypeList = /* @__PURE__ */ new Map();
    deviceTypes.forEach((deviceType) => deviceTypeList.set(deviceType.code, deviceType));
    this.deviceTypes = Array.from(deviceTypeList.values());
    this.name = deviceTypes[0].name;
  }
  addChildEndpoint(endpoint) {
    if (!(endpoint instanceof Endpoint)) {
      throw new import_general.InternalError("Only supported EndpointInterface implementation is Endpoint");
    }
    const id = endpoint.getNumber();
    if (this.childEndpoints.has(id)) {
      throw new import_general.ImplementationError(`Endpoint with id ${id} already exists as child from ${this.number}.`);
    }
    this.childEndpoints.set(id, endpoint);
    endpoint.setStructureChangedCallback(this.structureChangedCallback);
    this.structureChangedCallback();
  }
  getChildEndpoint(id) {
    return this.childEndpoints.get(id);
  }
  getChildEndpoints() {
    return Array.from(this.childEndpoints.values());
  }
  removeChildEndpoint(endpoint) {
    const id = endpoint.getNumber();
    const knownEndpoint = this.childEndpoints.get(id);
    if (knownEndpoint === void 0) {
      throw new import_general.ImplementationError(`Provided endpoint for deletion does not exist as child endpoint.`);
    }
    this.childEndpoints.delete(id);
    endpoint.removeFromStructure();
    this.structureChangedCallback();
  }
  determineUniqueID() {
    if (this.uniqueStorageKey !== void 0) {
      return `custom_${this.uniqueStorageKey}`;
    }
  }
  verifyRequiredClusters() {
    this.deviceTypes.forEach((deviceType) => {
      if (this.clusterClients.size > 0) {
        throw new import_general.NotImplementedError(`Devices with client clusters are not supported yet`);
      }
      deviceType.requiredClientClusters?.forEach((clusterId) => {
        const clusterName = (0, import_types.getClusterNameById)(clusterId);
        if (!this.clusterClients.has(clusterId)) {
          throw new import_general.ImplementationError(
            `Device type ${deviceType.name} (0x${deviceType.code.toString(
              16
            )}) requires cluster client ${clusterName}(0x${clusterId.toString(
              16
            )}) but it is not present on endpoint ${this.number}`
          );
        }
      });
    });
  }
  getAllClusterClients() {
    return Array.from(this.clusterClients.values());
  }
  /**
   * Hierarchical diagnostics of endpoint and children.
   */
  get [import_general.Diagnostic.value]() {
    return [
      import_general.Diagnostic.strong(this.name),
      import_general.Diagnostic.dict({
        "endpoint#": this.number,
        type: this.deviceTypes.map(
          ({ name, code, revision }) => `${name} (0x${code.toString(16)}, ${revision})`
        )
      }),
      import_general.Diagnostic.list([...this.#clusterDiagnostics(), ...this.getChildEndpoints()])
    ];
  }
  #clusterDiagnostics() {
    const clusterDiagnostics = new Array();
    const clients = this.getAllClusterClients();
    if (clients.length) {
      clusterDiagnostics.push([
        import_general.Diagnostic.strong("clients"),
        import_general.Diagnostic.list(clients.map((client) => this.#clusterClientDiagnostics(client)))
      ]);
    }
    const childs = this.getChildEndpoints();
    if (childs.length) {
      clusterDiagnostics.push([import_general.Diagnostic.strong("childs"), import_general.Diagnostic.list([])]);
    }
    return clusterDiagnostics;
  }
  #clusterClientDiagnostics(client) {
    const result = [
      import_general.Diagnostic.strong(client.name),
      import_general.Diagnostic.dict({
        id: import_general.Diagnostic.hex(client.id),
        rev: client.revision,
        flags: import_general.Diagnostic.asFlags({
          unknown: client.isUnknown
        })
      })
    ];
    const elementDiagnostic = Array();
    const features = client.supportedFeatures;
    const supportedFeatures = new Array();
    for (const featureName in features) {
      if (features[featureName] === true) supportedFeatures.push(featureName);
    }
    if (supportedFeatures.length) {
      elementDiagnostic.push([import_general.Diagnostic.strong("features"), supportedFeatures]);
    }
    if (Object.keys(client.attributes).length) {
      const clusterData = new Array();
      for (const attributeName in client.attributes) {
        if (attributeName.match(/^\d+$/)) continue;
        const attribute = client.attributes[attributeName];
        if (attribute === void 0 || !(attribute instanceof import_AttributeClient.SupportedAttributeClient)) continue;
        clusterData.push([
          attribute.name,
          import_general.Diagnostic.dict({
            id: import_general.Diagnostic.hex(attribute.id),
            val: attribute.getLocal(),
            flags: import_general.Diagnostic.asFlags({
              unknown: attribute instanceof import_AttributeClient.UnknownSupportedAttributeClient,
              fabricScoped: attribute.fabricScoped
            })
          })
        ]);
      }
      if (clusterData.length) {
        elementDiagnostic.push([import_general.Diagnostic.strong("attributes"), import_general.Diagnostic.list(clusterData)]);
      }
    }
    if (Object.keys(client.commands).length) {
      const clusterData = new Array();
      for (const commandName in client.commands) {
        if (commandName.match(/^\d+$/)) continue;
        const command = client.commands[commandName];
        if (command === void 0 || !client.isCommandSupportedByName(commandName)) continue;
        clusterData.push([commandName]);
      }
      if (clusterData.length) {
        elementDiagnostic.push([import_general.Diagnostic.strong("commands"), import_general.Diagnostic.list(clusterData)]);
      }
    }
    if (Object.keys(client.events).length) {
      const clusterData = new Array();
      for (const eventName in client.events) {
        if (eventName.match(/^\d+$/)) continue;
        const event = client.events[eventName];
        if (event === void 0) continue;
        clusterData.push([
          event.name,
          import_general.Diagnostic.dict({
            id: import_general.Diagnostic.hex(event.id)
          })
        ]);
      }
      if (clusterData.length) {
        elementDiagnostic.push([import_general.Diagnostic.strong("events"), import_general.Diagnostic.list(clusterData)]);
      }
    }
    if (elementDiagnostic.length) {
      result.push(import_general.Diagnostic.list(elementDiagnostic));
    }
    return result;
  }
}
//# sourceMappingURL=Endpoint.js.map
