"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 Parts_exports = {};
__export(Parts_exports, {
  Parts: () => Parts
});
module.exports = __toCommonJS(Parts_exports);
var import_general = require("#general");
var import_IdentityService = require("#node/server/IdentityService.js");
var import_Agent = require("../Agent.js");
var import_Endpoint = require("../Endpoint.js");
var import_errors = require("../errors.js");
var import_EndpointContainer = require("./EndpointContainer.js");
var import_EndpointLifecycle = require("./EndpointLifecycle.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("Parts");
class Parts extends import_EndpointContainer.EndpointContainer {
  #bubbleChange;
  constructor(endpoint) {
    super(endpoint);
    const lifecycle = this.owner.lifecycle;
    this.#bubbleChange = (type, endpoint2) => lifecycle.bubble(type, endpoint2);
  }
  add(child) {
    const endpoint = this.#endpointFor(child);
    if (this.has(endpoint)) {
      return;
    }
    if (this.owner.lifecycle.isReady) {
      this.#validateInsertion(endpoint, endpoint);
    }
    super.add(endpoint);
    endpoint.lifecycle.changed.on((type, endpoint2) => this.#bubbleChange(type, endpoint2));
    if (this.owner.lifecycle.isPartsReady) {
      if (!endpoint.construction.isErrorHandled) {
        endpoint.construction.onError((error) => logger.error(`Error initializing ${endpoint}:`, error));
      }
      endpoint.construction.start();
    }
    return endpoint;
  }
  delete(child) {
    const endpoint = this.#endpointFor(child);
    if (!super.delete(this.#endpointFor(child))) {
      return false;
    }
    const childLifeCycle = endpoint.lifecycle;
    childLifeCycle.changed.off(this.#bubbleChange);
    return true;
  }
  require(id) {
    const part = this.get(id);
    if (part === void 0) {
      throw new import_errors.PartNotFoundError(`Endpoint ${this.owner} has no part ${id}`);
    }
    return part;
  }
  has(identity) {
    if (typeof identity === "string") {
      for (const child of this) {
        if (child.maybeId === identity) {
          return true;
        }
      }
      return false;
    }
    return super.has(this.#endpointFor(identity));
  }
  indexOf(child) {
    const endpoint = this.#endpointFor(child);
    let index = 0;
    for (const other of this) {
      if (endpoint === other) {
        return index;
      }
      index++;
    }
    return -1;
  }
  /**
   * Initialize all uninitialized Parts.
   *
   * Invoked automatically by the owner after behaviors initialize.
   */
  initialize() {
    if (!this.owner.lifecycle.isReady) {
      throw new import_general.ImplementationError(`Cannot initialize parts because endpoint is not ready`);
    }
    const onPartsReady = () => this.owner.lifecycle.change(import_EndpointLifecycle.EndpointLifecycle.Change.PartsReady);
    if (!this.size) {
      onPartsReady();
      return;
    }
    for (const endpoint of this) {
      const isInactive = endpoint.construction.status === import_general.Lifecycle.Status.Inactive;
      if (isInactive || endpoint.construction.status === import_general.Lifecycle.Status.Initializing) {
        endpoint.construction.onError((error) => {
          logger.error(`Error initializing ${endpoint}:`, error);
        });
        if (isInactive) {
          endpoint.construction.start();
        }
      }
    }
    const onPartsCrashed = (errored) => {
      const essential = [...errored].filter((endpoint) => endpoint.lifecycle.isEssential);
      if (essential.length) {
        return new import_errors.EndpointPartsError(essential);
      }
    };
    let promise = import_general.Construction.all(this, onPartsCrashed);
    if (promise) {
      promise = promise.then(onPartsReady);
    } else {
      onPartsReady();
    }
    return promise;
  }
  #validateInsertion(forefather, endpoint, usedNumbers) {
    if (endpoint.lifecycle.hasNumber) {
      this.owner.env.get(import_IdentityService.IdentityService).assertNumberAvailable(endpoint.number, endpoint);
      if (usedNumbers?.has(endpoint.number)) {
        throw new import_IdentityService.IdentityConflictError(
          `Cannot add endpoint ${forefather} because descendents have conflicting definitions for endpoint number ${endpoint.number}`
        );
      }
    }
    if (!endpoint.hasParts) {
      return;
    }
    const children = endpoint.parts;
    if (!children.size) {
      return;
    }
    if (!usedNumbers) {
      usedNumbers = /* @__PURE__ */ new Set();
    }
    if (endpoint.lifecycle.hasNumber) {
      usedNumbers.add(endpoint.number);
    }
    for (const child of children) {
      this.#validateInsertion(forefather, child, usedNumbers);
    }
  }
  #endpointFor(child) {
    if (child instanceof import_Agent.Agent) {
      child = child.endpoint;
    }
    if (!(child instanceof import_Endpoint.Endpoint)) {
      if (child.type) {
        child.owner = this.owner;
      } else {
        child = {
          type: child,
          owner: this.owner
        };
      }
    }
    return import_Endpoint.Endpoint.partFor(child);
  }
}
//# sourceMappingURL=Parts.js.map
