"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 ClusterBehaviorType_exports = {};
__export(ClusterBehaviorType_exports, {
  ClusterBehaviorType: () => ClusterBehaviorType
});
module.exports = __toCommonJS(ClusterBehaviorType_exports);
var import_Events = require("#behavior/Events.js");
var import_general = require("@matter/general");
var import_model = require("@matter/model");
var import_types = require("@matter/types");
var import_Behavior = require("../Behavior.js");
var import_StateType = require("../state/StateType.js");
var import_ClusterBehaviorCache = require("./ClusterBehaviorCache.js");
var import_cluster_behavior_utils = require("./cluster-behavior-utils.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
function ClusterBehaviorType({
  namespace,
  base,
  features,
  schema,
  name,
  forClient,
  commandFactory
}) {
  if (schema === void 0) {
    if (base.schema?.tag === import_model.ElementTag.Cluster) {
      schema = base.schema;
    }
    if (!schema && namespace) {
      schema = namespace.schema;
    }
    if (!schema && namespace) {
      const nsId = namespace.id;
      if (nsId !== void 0) {
        schema = schemaForId(nsId);
      }
    }
  }
  if (!schema) {
    throw new import_general.ImplementationError("ClusterBehaviorType: no schema available");
  }
  if (features !== void 0) {
    schema = applyFeatureSelection(schema, features);
  } else {
    schema = syncFeatures(schema, namespace);
  }
  if (!namespace) {
    namespace = (0, import_types.ClusterType)(schema);
  }
  const useCache = name === void 0;
  if (useCache) {
    const cached = import_ClusterBehaviorCache.ClusterBehaviorCache.get(base, schema, forClient);
    if (cached) {
      return cached;
    }
    if (base.name.startsWith(schema.name)) {
      name = base.name;
    } else {
      name = `${schema.name}Behavior`;
    }
  }
  const context = {
    scope: (0, import_model.Scope)(schema),
    namespace,
    base,
    newProps: {},
    forClient,
    commandFactory
  };
  const supportedFeatures = computeFeatureFlags(schema);
  const type = (0, import_general.GeneratedClass)({
    name,
    base,
    staticProperties: {
      State: createDerivedState(context),
      Events: createDerivedEvents(context)
    },
    staticDescriptors: {
      id: {
        value: schema.propertyName,
        enumerable: true
      },
      cluster: {
        value: namespace,
        enumerable: true
      },
      features: {
        value: supportedFeatures,
        enumerable: true
      }
    },
    instanceDescriptors: createDefaultCommandDescriptors(context)
  });
  import_model.ClassSemantics.of(type).mutableModel = schema;
  if (type.schema !== schema) {
    Object.defineProperty(type, "schema", { value: schema });
  }
  schema.finalize();
  if (useCache) {
    import_ClusterBehaviorCache.ClusterBehaviorCache.set(base, schema, type);
  }
  return type;
}
const KNOWN_DEFAULTS = /* @__PURE__ */ Symbol("knownDefaults");
function createDerivedState({ scope, base, newProps }) {
  const BaseState = base["State"];
  if (BaseState === void 0) {
    throw new import_general.ImplementationError(`No state class defined for behavior class ${base.name}`);
  }
  const schema = scope.owner;
  const oldDefaults = new BaseState();
  let knownDefaults = BaseState[KNOWN_DEFAULTS];
  const props = {};
  for (const member of scope.membersOf(scope.owner, { conformance: "deconflicted" })) {
    const name = member.propertyName;
    if (props[name]) {
      props[name].push(member);
    } else {
      props[name] = [member];
    }
  }
  const defaults = {};
  for (const name in props) {
    const attrs = props[name];
    let propSchema;
    for (const attr of attrs) {
      if (!attr.effectiveConformance.applicabilityFor(scope)) {
        continue;
      }
      propSchema = attr;
      break;
    }
    if (!propSchema) {
      if (oldDefaults[name] !== void 0) {
        if (!knownDefaults) {
          knownDefaults = {};
        } else if (knownDefaults === BaseState[KNOWN_DEFAULTS]) {
          knownDefaults = { ...knownDefaults };
        }
        knownDefaults[name] = oldDefaults[name];
        defaults[name] = void 0;
      }
      continue;
    }
    newProps[name] = propSchema;
    if (propSchema.id === import_model.FeatureMap.id) {
      defaults[name] = computeFeatureFlags(schema);
      continue;
    }
    defaults[name] = selectDefaultValue(
      scope,
      oldDefaults[name] === void 0 ? knownDefaults?.[name] : oldDefaults[name],
      propSchema
    );
  }
  const StateType = (0, import_StateType.DerivedState)({
    name: `${schema.name}$State`,
    base: base.State,
    values: defaults
  });
  if (knownDefaults) {
    StateType[KNOWN_DEFAULTS] = knownDefaults;
  }
  return StateType;
}
function createDerivedEvents({ scope, base, newProps, forClient }) {
  const instanceDescriptors = {};
  const baseInstance = new base.Events();
  const eventNames = /* @__PURE__ */ new Set();
  const quieterImplementation = forClient ? import_Events.OnlineEvent : import_Events.QuietEvent;
  const applicableClusterEvents = /* @__PURE__ */ new Set();
  for (const event of scope.membersOf(scope.owner, {
    conformance: "conformant",
    tags: [import_model.ElementTag.Event]
  })) {
    const name = event.propertyName;
    applicableClusterEvents.add(name);
    if (baseInstance[name] !== void 0) {
      continue;
    }
    if (!forClient && !scope.hasOperationalSupport(event)) {
      continue;
    }
    eventNames.add(name);
    instanceDescriptors[name] = createEventDescriptor(
      name,
      event,
      event.quality.quieter ? quieterImplementation : import_Events.OnlineEvent
    );
  }
  for (const attrName in newProps) {
    const changing = `${attrName}$Changing`;
    const prop = newProps[attrName];
    if (baseInstance[changing] === void 0) {
      eventNames.add(changing);
      instanceDescriptors[changing] = createEventDescriptor(changing, prop, import_Events.OfflineEvent);
    }
    const changed = `${attrName}$Changed`;
    if (baseInstance[changed] === void 0) {
      eventNames.add(changed);
      instanceDescriptors[changed] = createEventDescriptor(
        changed,
        prop,
        prop.quality.quieter ? quieterImplementation : import_Events.OnlineEvent
      );
    }
  }
  return (0, import_general.GeneratedClass)({
    name: `${base.name}$Events`,
    base: base.Events,
    instanceDescriptors,
    initialize() {
      for (const name of eventNames) {
        this.addEvent(name);
      }
    }
  });
}
function schemaForId(id) {
  for (const child of import_model.Matter.children) {
    if (child.tag === import_model.ElementTag.Cluster && child.id === id) {
      return child;
    }
  }
  return void 0;
}
const configuredSchemaCache = /* @__PURE__ */ new Map();
function syncFeatures(schema, namespace) {
  let incomingFeatures;
  const nsSupportedFeatures = namespace?.supportedFeatures;
  if (nsSupportedFeatures) {
    incomingFeatures = new import_model.FeatureSet(nsSupportedFeatures);
  } else {
    return schema;
  }
  if (incomingFeatures.is(schema.supportedFeatures)) {
    return schema;
  }
  const featureKey = [...incomingFeatures].sort().join(",");
  let schemaBucket = configuredSchemaCache.get(schema);
  if (schemaBucket === void 0) {
    schemaBucket = {};
    configuredSchemaCache.set(schema, schemaBucket);
  } else {
    if (featureKey in schemaBucket) {
      return schemaBucket[featureKey];
    }
  }
  schema = schema.clone();
  schema.supportedFeatures = incomingFeatures;
  schemaBucket[featureKey] = schema;
  return schema;
}
function applyFeatureSelection(schema, features) {
  if (features === true) {
    const featureSet2 = new import_model.FeatureSet();
    for (const feature of schema.features) {
      featureSet2.add(feature.name);
    }
    return syncFeaturesFromSet(schema, featureSet2);
  }
  const featureSet = new import_model.FeatureSet();
  const model = schema;
  for (const name of features) {
    for (const feature of model.features) {
      if ((feature.title ?? feature.name) === name || feature.name === name) {
        featureSet.add(feature.name);
        break;
      }
    }
  }
  return syncFeaturesFromSet(schema, featureSet);
}
function syncFeaturesFromSet(schema, featureSet) {
  if (featureSet.is(schema.supportedFeatures)) {
    return schema;
  }
  const featureKey = [...featureSet].sort().join(",");
  let schemaBucket = configuredSchemaCache.get(schema);
  if (schemaBucket === void 0) {
    schemaBucket = {};
    configuredSchemaCache.set(schema, schemaBucket);
  } else if (featureKey in schemaBucket) {
    return schemaBucket[featureKey];
  }
  schema = schema.clone();
  schema.supportedFeatures = featureSet;
  schemaBucket[featureKey] = schema;
  return schema;
}
function computeFeatureFlags(schema) {
  const flags = {};
  for (const child of schema.featureMap.children) {
    const key = (0, import_general.camelize)(child.title ?? child.name);
    flags[key] = schema.supportedFeatures.has(child.name);
  }
  return flags;
}
const sourceFactory = /* @__PURE__ */ Symbol("source-factory");
function createDefaultCommandDescriptors({ scope, base, commandFactory }) {
  const result = {};
  const instance = (0, import_cluster_behavior_utils.introspectionInstanceOf)(base);
  const commandModels = scope.membersOf(scope.owner, { tags: [import_model.ElementTag.Command] });
  const names = new Set(commandModels.map((command) => command.propertyName));
  const commandsByName = new Map(commandModels.map((cmd) => [cmd.propertyName, cmd]));
  const conformantNames = new Set(
    scope.membersOf(scope.owner, { tags: [import_model.ElementTag.Command], conformance: "conformant" }).map((command) => command.propertyName)
  );
  for (const name of names) {
    let implementation;
    if (!conformantNames.has(name)) {
      if (instance[name] && instance[name] !== import_Behavior.Behavior.unimplemented) {
        continue;
      }
    }
    if (commandFactory) {
      if (instance[name]?.[sourceFactory] === commandFactory) {
        continue;
      }
      implementation = commandFactory(name, commandsByName.get(name));
      implementation[sourceFactory] = commandFactory;
    } else {
      if (instance[name]) {
        continue;
      }
      implementation = import_Behavior.Behavior.unimplemented;
    }
    result[name] = {
      value: implementation,
      writable: true
    };
  }
  return result;
}
function selectDefaultValue(scope, oldDefault, member) {
  if (oldDefault !== void 0) {
    return oldDefault;
  }
  if (!scope.hasOperationalSupport(member)) {
    return;
  }
  const effectiveDefault = (0, import_model.DefaultValue)(scope, member);
  if (effectiveDefault !== void 0) {
    if (member.effectiveMetatype === "bitmap") {
      return (0, import_model.DecodedBitmap)(member, effectiveDefault);
    }
    return effectiveDefault;
  }
  if (member.nullable) {
    return null;
  }
  switch (member.effectiveMetatype) {
    case import_model.Metatype.integer:
    case import_model.Metatype.float:
      return 0;
    case import_model.Metatype.boolean:
      return false;
    case import_model.Metatype.bitmap:
    case import_model.Metatype.object:
      return {};
    case import_model.Metatype.array:
      return [];
  }
}
function createEventDescriptor(name, schema, constructor) {
  return {
    get() {
      if (this.hasEvent(name, true)) {
        return this.getEvent(name);
      }
      const event = new constructor(schema, this);
      this.addEvent(name, event);
      return event;
    },
    enumerable: true
  };
}
//# sourceMappingURL=ClusterBehaviorType.js.map
