"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 Behavior_exports = {};
__export(Behavior_exports, {
  Behavior: () => Behavior
});
module.exports = __toCommonJS(Behavior_exports);
var import_Agent = require("#endpoint/Agent.js");
var import_general = require("#general");
var import_model = require("#model");
var import_StateType = require("./state/StateType.js");
var import_RootSupervisor = require("./supervision/RootSupervisor.js");
/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const BACKING = Symbol("endpoint-owner");
const STATE = Symbol("state");
const INTERNAL = Symbol("internal");
const EVENTS = Symbol("events");
const SUPERVISOR = Symbol("supervisor");
class Behavior {
  #agent;
  /**
   * Each behavior implementation has an ID that uniquely identifies the type of behavior.  An Endpoint may only have
   * one behavior with the specified ID.
   *
   * Endpoint instances store each behavior in a property with the same name as the behavior's ID.
   *
   * EndpointBuilder also uses the ID when replacing behaviors using the with() builder method.
   */
  static id;
  /**
   * A behavior's schema controls access to data, commands and events.
   *
   * Schema is inferred from the methods and properties of the behavior but you can specify explicitly for additional
   * control.
   */
  static get schema() {
    return (0, import_model.Schema)(this) ?? import_model.Schema.empty;
  }
  /**
   * By default behaviors load lazily as they are accessed.  You can set this flag to true to force behaviors to load
   * immediately when the endpoint initializes.
   */
  static early = false;
  /**
   * The agent that owns the behavior.
   */
  get agent() {
    return this.#agent;
  }
  /**
   * The endpoint that owns behavior's agent.
   */
  get endpoint() {
    return this.#agent.endpoint;
  }
  /**
   * The context in which the behavior operates.
   */
  get context() {
    return this.#agent.context;
  }
  /**
   * The endpoint's environment.
   */
  get env() {
    return this.endpoint.env;
  }
  /**
   * The Behavior's type.
   */
  get type() {
    return this.constructor;
  }
  constructor(agent, backing) {
    this.#agent = agent;
    this[BACKING] = backing;
    if (agent !== void 0) {
      agent[import_Agent.INSTALL_BEHAVIOR](this);
    }
  }
  /**
   * The data supervisor for the behavior.  The supervisor controls validation and access to behavior data.
   */
  static get supervisor() {
    if (Object.hasOwn(this, SUPERVISOR)) {
      return this[SUPERVISOR];
    }
    return this[SUPERVISOR] = import_RootSupervisor.RootSupervisor.for((0, import_model.Schema)(this) ?? import_model.Schema.empty);
  }
  /**
   * Implementation of endpoint-scoped state.  Subclasses may override to extend.
   */
  static State = import_StateType.EmptyState;
  /**
   * Implementation of internal state.  Subclasses may override to extend.
   */
  static Internal = import_StateType.EmptyState;
  /**
   * Implementation of the events property.  Subclasses may override to extend.
   */
  static Events = import_general.EventEmitter;
  /**
   * Behaviors are ephemeral and should not perform initialization in their constructor.  They can override this
   * method instead.
   *
   * This method may be synchronous or asyncronous.  If asynchronous, the behavior will not be available for external
   * use until initialization completes.
   */
  initialize(_options) {
  }
  /**
   * Release resources.  This is the public API for releasing application resources held by behaviors in internal
   * state.
   */
  [Symbol.asyncDispose]() {
  }
  /**
   * Description used in diagnostic messages.
   */
  toString() {
    return `${this.endpoint}.${this.type.id}`;
  }
  /**
   * Install a {@link Reactor}.
   *
   * Important: The reactor MUST be a real JS function - arrow functions will not work!
   */
  reactTo(observable, reactor, options) {
    this[BACKING].reactTo(observable, reactor, options);
  }
  maybeReactTo(observable, reactor, options) {
    if (observable) {
      this.reactTo(observable, reactor, options);
    }
  }
  /**
   * Stop reacting to specified conditions.
   *
   * @param selector the observable and/or reactor to disable; if omitted terminates all reaction
   */
  stopReacting(selector) {
    return this[BACKING].stopReacting(selector);
  }
  /**
   * Create a generic callback function that has the same properties as a {@link Reactor}.
   *
   * Like a reactor, the callback's "this" will be bound to an active Behavior instance.
   * Because of this: The reactor MUST be a real JS function - arrow functions will not work!
   */
  callback(reactor, options) {
    const observable = (0, import_general.Observable)();
    this.reactTo(observable, reactor, options);
    return observable.emit.bind(observable);
  }
  /**
   * Create an async callback.
   *
   * @see {@link callback}
   */
  asyncCallback(reactor, options) {
    const observable = (0, import_general.AsyncObservable)();
    this.reactTo(observable, reactor, options);
    return observable.emit.bind(observable);
  }
  /**
   * Does this behavior support functionality of a specific implementation?
   */
  static supports(other) {
    return this === other || this.prototype instanceof other;
  }
  /**
   * Default state values.
   */
  static get defaults() {
    return new this.State();
  }
  /**
   * Create a new behavior with different default state values.
   */
  static set(defaults) {
    return (0, import_general.GeneratedClass)({
      name: this.name,
      base: this,
      staticProperties: {
        State: (0, import_StateType.DerivedState)({
          name: `${this.name}$State`,
          base: this.State,
          values: defaults
        })
      }
    });
  }
  /**
   * Explicitly reference other {@link Behavior}s as dependencies, ensuring this behavior is destroyed first.
   *
   * This probably won't be commonly necessary.  If it is we can instrument Agent to collect dependencies
   * automatically.
   */
  static dependencies;
  get [import_general.Transaction.Resource.reference]() {
    return this[BACKING].datasource;
  }
}
Object.defineProperties(Behavior.prototype, {
  state: {
    get() {
      if (!this[STATE]) {
        this[STATE] = this[BACKING].datasource.reference(this.context);
      }
      return this[STATE];
    },
    enumerable: true
  },
  internal: {
    get() {
      if (!this[INTERNAL]) {
        this[INTERNAL] = this[BACKING].getInternal();
      }
      return this[INTERNAL];
    },
    enumerable: false
  },
  events: {
    get() {
      if (!this[EVENTS]) {
        this[EVENTS] = this[BACKING].events;
      }
      return this[EVENTS];
    },
    enumerable: true
  }
});
Object.defineProperties(Behavior, {
  [import_model.ClassSemantics.extend]: {
    value(decoration) {
      const type = decoration.new;
      if (Object.hasOwn(type, "schema") && type.schema !== void 0) {
        decoration.mutableModel = type.schema;
      }
      const { State, Events, defaults } = type;
      if (!State || !defaults) {
        return;
      }
      if (import_model.ClassSemantics.hasOwnSemantics(State)) {
        const stateSemantics = import_model.Semantics.classOf(State);
        stateSemantics.mutableModel = decoration.mutableModel;
      }
      if (import_model.ClassSemantics.hasOwnSemantics(Events)) {
        const eventSemantics = import_model.Semantics.classOf(Events);
        eventSemantics.mutableModel = decoration.mutableModel;
      }
      decoration.defineUnknownMembers(defaults);
    }
  }
});
((Behavior2) => {
  function unimplemented(..._args) {
    throw new import_general.NotImplementedError();
  }
  Behavior2.unimplemented = unimplemented;
})(Behavior || (Behavior = {}));
//# sourceMappingURL=Behavior.js.map
