/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { ClusterBehavior } from "#behavior/cluster/ClusterBehavior.js";
import { ValidatedElements } from "#behavior/cluster/ValidatedElements.js";
import { camelize, ImplementationError } from "#general";
import { FeatureSet, FieldValue, Schema } from "#model";
import { TlvNoResponse } from "#types";
import { BehaviorBacking } from "./BehaviorBacking.js";
const NoElements = /* @__PURE__ */ new Set();
class FeatureMismatchError extends ImplementationError {
}
class ServerBehaviorBacking extends BehaviorBacking {
  #elements;
  get elements() {
    return this.#elements;
  }
  invokeInitializer(behavior, options) {
    const finalizeState = () => {
      this.#applyTransitiveDefaults(behavior.state);
      if (behavior instanceof ClusterBehavior) {
        this.#configureElements(behavior);
      } else {
        this.#elements = {
          features: NoElements,
          attributes: NoElements,
          commands: NoElements,
          events: NoElements
        };
      }
      const context = behavior.context;
      this.datasource.validate(context, behavior.state);
    };
    const promise = super.invokeInitializer(behavior, options);
    if (promise) {
      return promise.then(finalizeState);
    }
    finalizeState();
  }
  /**
   * Schema may specify that state fields default to the value of another field.  We apply these defaults after
   * initialization when the other field should be defined.
   */
  #applyTransitiveDefaults(state) {
    const schema = this.type.schema;
    if (!schema) {
      return;
    }
    for (const member of this.type.supervisor.membersOf(schema)) {
      const name = camelize(member.name);
      if (state[name] === void 0) {
        const referenced = FieldValue.referenced(member.default);
        if (referenced) {
          const val = state[camelize(referenced)];
          if (val !== void 0) {
            state[name] = val;
          }
        }
      }
    }
  }
  #configureElements(behavior) {
    const validation = new ValidatedElements(behavior.constructor, behavior);
    validation.report();
    const globals = behavior.state;
    const attributeDefs = behavior.cluster.attributes;
    globals.attributeList = [...validation.attributes].map((name) => attributeDefs[name].id);
    const commandDefs = behavior.cluster.commands;
    const commands = [...validation.commands].map((name) => commandDefs[name]);
    globals.acceptedCommandList = commands.map((command) => command.requestId);
    globals.generatedCommandList = [
      ...new Set(
        commands.filter((command) => command.responseSchema !== TlvNoResponse).map((command) => command.responseId)
      )
    ];
    const schema = Schema(behavior.type);
    if (schema.tag === "cluster") {
      const { supportedFeatures, featureMap } = Schema(behavior.type);
      const { featuresSupported, featuresAvailable } = FeatureSet.normalize(
        featureMap,
        new FeatureSet(globals.featureMap)
      );
      for (const name of featuresAvailable) {
        if (supportedFeatures.has(name) !== featuresSupported.has(name)) {
          throw new FeatureMismatchError(
            `The featureMap for ${behavior} does not match the implementation; please use ${behavior.type.name}.with("FeatureName") to configure features`
          );
        }
      }
    }
    this.#elements = {
      features: behavior.type.schema.supportedFeatures ?? /* @__PURE__ */ new Set(),
      attributes: validation.attributes,
      commands: validation.commands,
      events: validation.events
    };
  }
}
export {
  FeatureMismatchError,
  ServerBehaviorBacking
};
//# sourceMappingURL=ServerBehaviorBacking.js.map
