/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { createPromise, deepCopy, isObject, Logger, MaybePromise, Seconds, withTimeout } from "#general";
import { OccurrenceManager } from "#protocol";
const logger = Logger.get("FabricScopedDataHandler");
async function forBehaviors(endpoint, callback) {
  for (const type of Object.values(endpoint.behaviors.supported)) {
    const cluster = type?.cluster;
    if (!cluster) {
      continue;
    }
    const elements = endpoint.behaviors.elementsOf(type);
    if (elements.attributes.size || elements.events.size) {
      await callback(type, cluster, elements);
    }
  }
}
async function sanitizeAttributeData(endpoint, type, cluster, supportedAttributes, allowedIndices) {
  const stateUpdatePromises = new Array();
  const stateUpdate = {};
  for (const attributeName of supportedAttributes) {
    const attr = cluster.attributes[attributeName];
    if (attr.fabricScoped) {
      const value = endpoint.stateOf(type)[attributeName];
      if (Array.isArray(value) && value.length > 0) {
        const filtered = deepCopy(value).filter((entry) => allowedIndices.includes(entry.fabricIndex));
        if (filtered.length !== value.length) {
          stateUpdate[attributeName] = filtered;
        }
      }
    }
  }
  if (Object.keys(stateUpdate).length > 0) {
    const { resolver, promise } = createPromise();
    endpoint.eventsOf(type).stateChanged?.on(resolver);
    try {
      await endpoint.setStateOf(type, stateUpdate);
      stateUpdatePromises.push(withTimeout(Seconds(5), promise));
    } catch (error) {
      logger.warn(
        `Could not sanitize fabric-scoped attributes for cluster ${cluster.name} on endpoint ${endpoint.id}`,
        error
      );
    }
  }
  return stateUpdatePromises;
}
async function limitNodeDataToAllowedFabrics(node, allowedIndices) {
  const fabricRelevantEvents = /* @__PURE__ */ new Set();
  const stateUpdatePromises = new Array();
  await node.visit(async (endpoint) => {
    await forBehaviors(endpoint, async (type, cluster, elements) => {
      if (elements.attributes.size) {
        stateUpdatePromises.push(
          ...await sanitizeAttributeData(endpoint, type, cluster, elements.attributes, allowedIndices)
        );
      }
      if (elements.events.size) {
        for (const eventName of elements.events) {
          const event = cluster.events[eventName];
          if (event.schema.isFabricScoped) {
            fabricRelevantEvents.add(`${cluster.id}-${event.id}`);
          }
        }
      }
    });
  });
  await Promise.allSettled(stateUpdatePromises);
  if (fabricRelevantEvents.size > 0) {
    const occurrences = node.env.get(OccurrenceManager);
    for await (const event of occurrences.get()) {
      if (fabricRelevantEvents.has(`${event.clusterId}-${event.eventId}`) && isObject(event.payload) && !allowedIndices.includes(event.payload.fabricIndex)) {
        const result = occurrences.remove(event.number);
        if (MaybePromise.is(result)) {
          await result;
        }
      }
    }
  }
}
async function limitEndpointAttributeDataToAllowedFabrics(endpoint, allowedIndices) {
  const stateUpdatePromises = new Array();
  await forBehaviors(endpoint, async (type, cluster, elements) => {
    if (elements.attributes.size) {
      stateUpdatePromises.push(
        ...await sanitizeAttributeData(endpoint, type, cluster, elements.attributes, allowedIndices)
      );
    }
  });
  await Promise.allSettled(stateUpdatePromises);
}
export {
  limitEndpointAttributeDataToAllowedFabrics,
  limitNodeDataToAllowedFabrics
};
//# sourceMappingURL=FabricScopedDataHandler.js.map
