/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { Behavior } from "#behavior/Behavior.js";
import { Endpoint } from "#endpoint/Endpoint.js";
import { ImportError, Logger, MaybePromise } from "@matter/general";
import { load } from "@matter/node/load";
const logger = Logger.get("Plugins");
class Plugins {
  #node;
  constructor(node) {
    this.#node = node;
  }
  /**
   * Load and apply all plugins.  Called once during node initialization.
   */
  async load() {
    const specifiers = Array();
    for (const path of ["plugins", `nodes.${this.#node.id}.plugins`]) {
      const value = this.#node.env.vars.get(path);
      if (typeof value === "string" && value.length) {
        for (const segment of value.split(",")) {
          const trimmed = segment.trim();
          if (trimmed.length && !specifiers.includes(trimmed)) {
            specifiers.push(trimmed);
          }
        }
      }
    }
    for (const specifier of specifiers) {
      const mod = await this.#loadModule(specifier);
      this.#applyModule(specifier, mod);
    }
  }
  async #loadModule(specifier) {
    try {
      const mod = load(specifier);
      if (MaybePromise.is(mod)) {
        return await mod;
      }
      return mod;
    } catch (e) {
      throw new ImportError(`Failed to load plugin "${specifier}": ${e}`);
    }
  }
  #applyModule(specifier, mod) {
    if (typeof mod.install === "function") {
      const result = mod.install(this.#node);
      if (MaybePromise.is(result)) {
        throw new ImportError(
          `Plugin "${specifier}" install function returned a promise; install must be synchronous`
        );
      }
      return;
    }
    const serverBehaviors = Array();
    const deviceTypes = Array();
    for (const [name, value] of Object.entries(mod)) {
      if (name === "default" || name.startsWith("_") || value === void 0 || value === null) {
        continue;
      }
      if (name.endsWith("Server") && isBehaviorType(value)) {
        serverBehaviors.push(value);
      } else if (isEndpointType(value)) {
        deviceTypes.push(value);
      }
    }
    if (serverBehaviors.length === 0 && deviceTypes.length === 0) {
      logger.debug("Plugin", specifier, "loaded (side-effect only)");
      return;
    }
    for (const behavior of serverBehaviors) {
      logger.debug("Plugin", specifier, "installing behavior", behavior.id);
      this.#node.behaviors.require(behavior);
    }
    if (deviceTypes.length > 1) {
      const names = deviceTypes.map((d) => `DeviceType "${d.name}"`);
      throw new ImportError(
        `Plugin "${specifier}" exports multiple device types (${names.join(", ")}). Add a named "install" export to specify how the plugin should be applied.`
      );
    }
    if (deviceTypes.length === 1) {
      logger.debug("Plugin", specifier, "adding endpoint", deviceTypes[0].name);
      this.#node.parts.add(new Endpoint(deviceTypes[0]));
    }
  }
}
function isBehaviorType(value) {
  return typeof value === "function" && value.prototype instanceof Behavior;
}
function isEndpointType(value) {
  if (typeof value !== "object" || value === null) {
    return false;
  }
  const candidate = value;
  return typeof candidate.name === "string" && typeof candidate.deviceType === "number" && typeof candidate.deviceRevision === "number" && typeof candidate.behaviors === "object" && candidate.behaviors !== null;
}
export {
  Plugins
};
//# sourceMappingURL=Plugins.js.map
