"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 PeerBehavior_exports = {};
__export(PeerBehavior_exports, {
  PeerBehavior: () => PeerBehavior
});
module.exports = __toCommonJS(PeerBehavior_exports);
var import_ClusterBehavior = require("#behavior/cluster/ClusterBehavior.js");
var import_ClusterBehaviorType = require("#behavior/cluster/ClusterBehaviorType.js");
var import_general = require("#general");
var import_model = require("#model");
var import_types = require("#types");
var import_ClientCommandMethod = require("./ClientCommandMethod.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const BIT_BLOCK_SIZE = Math.log2(Number.MAX_SAFE_INTEGER);
const discoveredCache = {};
const knownCache = /* @__PURE__ */ new WeakMap();
const isPeer = /* @__PURE__ */ Symbol("is-peer");
function PeerBehavior(shape) {
  let type;
  switch (shape.kind) {
    case "known":
      if (Object.hasOwn(shape.behavior, isPeer)) {
        return shape.behavior;
      }
      type = instrumentKnownShape(shape);
      break;
    case "discovered":
      type = instrumentDiscoveredShape(shape);
      break;
    default:
      throw new import_general.InternalError(`Unknown cluster shape kind ${shape.kind}`);
  }
  type[isPeer] = true;
  return type;
}
function instrumentDiscoveredShape(shape) {
  const analysis = DiscoveredShapeAnalysis(shape);
  const fingerprint = createFingerprint(analysis);
  let type = discoveredCache[fingerprint];
  if (type) {
    return type;
  }
  let baseType;
  const standardCluster = import_types.ClusterRegistry.get(shape.id);
  if (standardCluster && !standardCluster.name.startsWith("Unknown cluster 0x")) {
    baseType = import_ClusterBehavior.ClusterBehavior.for(standardCluster);
  }
  type = discoveredCache[fingerprint] = generateDiscoveredType(analysis, baseType);
  return type;
}
function instrumentKnownShape(shape) {
  let type = knownCache.get(shape.behavior);
  if (type) {
    return type;
  }
  const base = shape.behavior;
  type = (0, import_ClusterBehaviorType.ClusterBehaviorType)({
    base,
    cluster: base.cluster,
    schema: base.schema,
    name: `${base.schema.name}Client`,
    forClient: true,
    commandFactory: import_ClientCommandMethod.ClientCommandMethod
  });
  knownCache.set(shape.behavior, type);
  return type;
}
function generateDiscoveredType(analysis, baseType) {
  let { schema } = analysis;
  let isExtended;
  let cluster;
  if (baseType) {
    isExtended = false;
    if (!import_ClusterBehavior.ClusterBehavior.is(baseType)) {
      throw new import_general.InternalError(`Base for cluster ${analysis.schema.name} is not a ClusterBehavior`);
    }
    cluster = baseType.cluster;
  } else {
    isExtended = true;
    cluster = (0, import_types.MutableCluster)({ id: schema.id, name: schema.name, revision: schema.revision });
    baseType = import_ClusterBehavior.ClusterBehavior;
  }
  const { attrSupportOverrides, extraAttrs, commandSupportOverrides, extraCommands } = analysis;
  let supportedFeatures = analysis.shape.features;
  if (typeof supportedFeatures === "number") {
    supportedFeatures = cluster.attributes.featureMap.schema.decode(supportedFeatures);
  }
  if (supportedFeatures === void 0) {
    supportedFeatures = {};
  }
  const featureNames = Object.entries(supportedFeatures).filter(([, v]) => v).map(([k]) => k);
  if (featureNames.length) {
    extendSchema();
    cluster = new import_types.ClusterComposer(cluster, true).compose(featureNames.map(import_general.capitalize));
  }
  if (schema.revision !== analysis.shape.revision || extraAttrs.size || extraCommands.size || attrSupportOverrides.size || commandSupportOverrides.size) {
    extendSchema();
    cluster = {
      ...cluster,
      supportedFeatures,
      attributes: { ...cluster.attributes },
      commands: { ...cluster.commands }
    };
    if (attrSupportOverrides.size) {
      for (const [attr, isSupported] of attrSupportOverrides.entries()) {
        schema.children.push(attr.extend({ operationalIsSupported: isSupported }));
      }
    }
    for (const id of extraAttrs) {
      const name = createUnknownName("attr", id);
      cluster.attributes[(0, import_general.camelize)(name, false)] = (0, import_types.UnknownAttribute)(id);
      schema.children.push(new import_model.AttributeModel({ id, name, type: "any" }));
    }
    if (commandSupportOverrides.size) {
      for (const [command, isSupported] of commandSupportOverrides.entries()) {
        schema.children.push(command.extend({ operationalIsSupported: isSupported }));
      }
    }
    for (const id of extraCommands) {
      const name = createUnknownName("command", id);
      cluster.commands[(0, import_general.camelize)(name, false)] = (0, import_types.UnknownCommand)(id, import_types.TlvAny, 0, import_types.TlvNoResponse);
      schema.children.push(new import_model.CommandModel({ id, name, type: "any" }));
    }
  }
  return (0, import_ClusterBehaviorType.ClusterBehaviorType)({
    base: baseType,
    cluster,
    schema,
    name: `${schema.name}Client`,
    forClient: true,
    commandFactory: import_ClientCommandMethod.ClientCommandMethod
  });
  function extendSchema() {
    if (isExtended) {
      return;
    }
    schema = schema.extend();
    isExtended = true;
  }
}
function createFingerprint(analysis) {
  const fingerprint = [analysis.shape.id];
  if (analysis.featureBitmap) {
    fingerprint.push("f", analysis.featureBitmap);
  }
  if (analysis.attrSupportOverrides.size) {
    addSupportFingerprints("a", analysis.attrSupportOverrides);
  }
  if (analysis.extraAttrs.size) {
    fingerprint.push("a", createElementFingerprint(analysis.extraAttrs));
  }
  if (analysis.commandSupportOverrides.size) {
    addSupportFingerprints("c", analysis.commandSupportOverrides);
  }
  if (analysis.extraCommands.size) {
    fingerprint.push("c", createElementFingerprint(analysis.extraCommands));
  }
  return fingerprint.join(";");
  function createElementFingerprint(ids) {
    const blocks = {};
    for (const id of ids) {
      const block = Math.floor(id / BIT_BLOCK_SIZE);
      blocks[block] = (blocks[block] ?? 0) | 1 << id % BIT_BLOCK_SIZE;
    }
    return Object.entries(blocks).sort(([a], [b]) => a.localeCompare(b)).map(([block, map]) => block ? `${block}:${map}` : map).join(",");
  }
  function addSupportFingerprints(prefix, elements) {
    let supported;
    let unsupported;
    for (const [{ id }, isSupported] of elements) {
      if (id === void 0) {
        continue;
      }
      if (isSupported) {
        if (supported) {
          supported.push(id);
        } else {
          supported = [id];
        }
      } else {
        if (unsupported) {
          unsupported.push(id);
        } else {
          unsupported = [id];
        }
      }
    }
    if (supported) {
      fingerprint.push(`${prefix}+`, createElementFingerprint(supported));
    }
    if (unsupported) {
      fingerprint.push(`${prefix}-`, createElementFingerprint(unsupported));
    }
  }
}
function createUnknownName(prefix, id) {
  return `${prefix}$${id.toString(16)}`;
}
function DiscoveredShapeAnalysis(shape) {
  const standardCluster = import_model.Matter.get(import_model.ClusterModel, shape.id);
  const schema = standardCluster ?? new import_model.ClusterModel({ id: shape.id, name: createUnknownName("Cluster", shape.id), revision: shape.revision });
  let featureBitmap;
  if (typeof shape.features === "number") {
    featureBitmap = shape.features;
  } else {
    featureBitmap = (0, import_model.EncodedBitmap)(schema.featureMap, shape.features ?? {});
  }
  const attrSupportOverrides = /* @__PURE__ */ new Map();
  const extraAttrs = new Set(shape.attributes ?? []);
  for (const attr of schema.attributes) {
    maybeOverrideSupport(standardCluster, attr, extraAttrs, attrSupportOverrides);
    extraAttrs.delete(attr.id);
  }
  const commandSupportOverrides = /* @__PURE__ */ new Map();
  const extraCommands = new Set(shape.commands ?? []);
  for (const command of schema.commands) {
    maybeOverrideSupport(standardCluster, command, extraCommands, commandSupportOverrides);
    extraCommands.delete(command.id);
  }
  return {
    schema,
    featureBitmap,
    shape,
    attrSupportOverrides,
    extraAttrs,
    commandSupportOverrides,
    extraCommands
  };
}
function maybeOverrideSupport(standardCluster, element, supported, overrides) {
  if (!standardCluster) {
    return;
  }
  const isSupported = supported === true || supported.has(element.id);
  const applicability = element.effectiveConformance.applicabilityFor(standardCluster);
  if (!isSupported) {
    if (applicability === import_model.Conformance.Applicability.Mandatory) {
      overrides.set(element, false);
    }
  } else {
    if (applicability !== import_model.Conformance.Applicability.Mandatory) {
      overrides.set(element, true);
    }
  }
}
//# sourceMappingURL=PeerBehavior.js.map
