"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 ValidatedElements_exports = {};
__export(ValidatedElements_exports, {
  ClusterElementError: () => ClusterElementError,
  ClusterImplementationError: () => ClusterImplementationError,
  ValidatedElements: () => ValidatedElements
});
module.exports = __toCommonJS(ValidatedElements_exports);
var import_general = require("@matter/general");
var import_Behavior = require("../Behavior.js");
var import_cluster_behavior_utils = require("./cluster-behavior-utils.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("ValidatedElements");
class ClusterImplementationError extends import_general.MatterAggregateError {
  constructor(name, errors) {
    super(
      errors,
      import_general.Diagnostic.upgrade(
        `Cluster behavior ${name} has fatal implementation errors`,
        import_general.Diagnostic.squash("Cluster behavior", import_general.Diagnostic.strong(name), "has fatal implementation errors")
      )
    );
  }
}
class ClusterElementError extends import_general.ImplementationError {
  constructor(element, message) {
    super(
      import_general.Diagnostic.upgrade(
        `Error in ${element}: ${message}`,
        import_general.Diagnostic.squash("Error in ", import_general.Diagnostic.strong(element), ": ", message)
      )
    );
  }
}
class ValidatedElements {
  /**
   * Supported attributes.
   */
  attributes = /* @__PURE__ */ new Set();
  /**
   * Supported commands.
   */
  commands = /* @__PURE__ */ new Set();
  /**
   * Supported events.
   */
  events = /* @__PURE__ */ new Set();
  /**
   * A list of implementation errors, if any.
   */
  errors;
  #name;
  #type;
  #instance;
  #cluster;
  /**
   * Obtain validation information.
   *
   * Validation may run against the type alone or with a specific instance of the behavior.  The latter option allows
   * for per-instance specialization.
   *
   * @param type the behavior type to analyze
   * @param instance optional concrete instance of the behavior
   */
  constructor(type, instance) {
    this.#type = type;
    this.#instance = instance;
    this.#name = type.name;
    this.#cluster = type.cluster;
    if (typeof type !== "function") {
      this.error(void 0, "Is not a class", true);
    }
    if (this.#cluster === void 0) {
      this.error("cluster", "Property missing", true);
      return;
    }
    if (typeof this.#cluster !== "object") {
      this.error("cluster", "Property is not an object", true);
      return;
    }
    if (instance !== void 0 && (instance === null || typeof instance !== "object")) {
      this.error("instance", "Is not an object", true);
    }
    this.#validateAttributes();
    this.#validateCommands();
    this.#validateEvents();
  }
  /**
   * If there are errors, log and throw an exception.
   */
  report() {
    if (!this.errors) {
      return;
    }
    let fatalErrors;
    for (const { element, message, fatal } of this.errors) {
      const error = new ClusterElementError(element, message);
      if (fatal) {
        if (!fatalErrors) {
          fatalErrors = [];
        }
        fatalErrors.push(error);
      } else {
        logger.warn(error.message);
      }
    }
    if (fatalErrors) {
      throw new ClusterImplementationError(this.#type.name, fatalErrors);
    }
  }
  #validateAttributes() {
    const attributes = this.#cluster.attributes;
    if (!attributes) {
      this.error("cluster.attributes", "Property missing", true);
      return;
    }
    let state;
    if (this.#instance) {
      state = this.#instance.state;
    } else {
      const constructor = this.#type.State;
      if (!constructor) {
        this.error("State", "Property missing", true);
        return;
      }
      try {
        state = new constructor();
      } catch (e) {
        this.error("State", "Not constructable", true);
        return;
      }
    }
    for (const name in attributes) {
      const attr = attributes[name];
      if (!attr) {
        this.error(`cluster.attributes.${name}`, "Undefined element in cluster definition", true);
        continue;
      }
      if (state[name] === void 0) {
        if (!attr.optional) {
          this.error(`State.${name}`, "Mandatory element unsupported", false);
        }
        continue;
      }
      this.attributes.add(name);
    }
  }
  #validateCommands() {
    const commands = this.#cluster.commands;
    if (!commands) {
      this.error("cluster.commands", "Property missing", true);
      return;
    }
    let implementations;
    if (this.#instance) {
      implementations = this.#instance;
    } else {
      try {
        implementations = (0, import_cluster_behavior_utils.introspectionInstanceOf)(this.#type);
      } catch (e) {
        this.error("constructor", "Not constructable", true);
        return;
      }
    }
    for (const name in commands) {
      const command = commands[name];
      if (!command) {
        this.error(`cluster.commands.${name}`, "Undefined element in cluster definition", true);
        continue;
      }
      const implementation = implementations[name];
      if (!(name in implementations) || implementation === void 0) {
        if (!command.optional) {
          this.error(name, `Implementation missing`, true);
        }
        continue;
      }
      if (typeof implementation !== "function") {
        this.error(name, `Implementation is not a function`, true);
        continue;
      }
      if (implementation === import_Behavior.Behavior.unimplemented) {
        if (!command.optional) {
          if (this.#name.match(/^(?:Groups|Scenes|GroupKeyManagement)(?:Server|Behavior)/)) {
            continue;
          }
          this.error(name, `Throws unimplemented exception`, false);
        }
        continue;
      }
      this.commands.add(name);
    }
  }
  #validateEvents() {
    const expected = this.#cluster.events;
    if (typeof expected !== "object" || expected === null) {
      this.error("cluster.events", "Invalid definition", true);
      return;
    }
    const constructor = this.#type.Events;
    if (!constructor) {
      this.error("Events", "Implementation missing", true);
      return;
    }
    let emitters;
    if (this.#instance) {
      emitters = this.#instance.events;
    } else {
      try {
        emitters = new constructor();
      } catch (e) {
        this.error("Events", "Not constructable", true);
        return;
      }
    }
    for (const name in expected) {
      const event = expected[name];
      if (!event) {
        this.error(`cluster.events.${name}`, "Undefined element in cluster definition", true);
        continue;
      }
      if (!(name in emitters)) {
        if (!event.optional) {
          this.error(`cluster.events.${name}`, "Implementation missing", true);
        }
        continue;
      }
      this.events.add(name);
    }
  }
  error(element, message, fatal) {
    if (!this.errors) {
      this.errors = [];
    }
    const name = element === void 0 ? this.#name : `${this.#name}.${element}`;
    this.errors?.push({ element: name, message, fatal });
  }
}
//# sourceMappingURL=ValidatedElements.js.map
