"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 ServerNetworkRuntime_exports = {};
__export(ServerNetworkRuntime_exports, {
  ServerNetworkRuntime: () => ServerNetworkRuntime
});
module.exports = __toCommonJS(ServerNetworkRuntime_exports);
var import_general = require("#general");
var import_TransactionalInteractionServer = require("#node/server/TransactionalInteractionServer.js");
var import_protocol = require("#protocol");
var import_CommissioningServer = require("../commissioning/CommissioningServer.js");
var import_ProductDescriptionServer = require("../product-description/ProductDescriptionServer.js");
var import_SessionsBehavior = require("../sessions/SessionsBehavior.js");
var import_NetworkRuntime = require("./NetworkRuntime.js");
/**
 * @license
 * Copyright 2022-2024 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
function convertNetworkEnvironmentType(type) {
  const convertedType = typeof type === "string" ? import_general.InterfaceType[type] : type;
  if (typeof convertedType !== "number" || convertedType < 1 || convertedType > 4) {
    return void 0;
  }
  return convertedType;
}
class ServerNetworkRuntime extends import_NetworkRuntime.NetworkRuntime {
  #interactionServer;
  #mdnsBroadcaster;
  #bleBroadcaster;
  #bleTransport;
  #observers = new import_general.ObserverGroup(this);
  get owner() {
    return super.owner;
  }
  /**
   * Access the MDNS broadcaster for the node.
   */
  get mdnsBroadcaster() {
    if (!this.#mdnsBroadcaster) {
      this.#mdnsBroadcaster = this.owner.env.get(import_protocol.MdnsService).createInstanceBroadcaster(this.owner.state.network.operationalPort);
    }
    return this.#mdnsBroadcaster;
  }
  get networkInterfaceConfiguration() {
    const interfaceConfig = this.owner.env.vars.get(
      "network.interface",
      {}
    );
    return Object.entries(interfaceConfig).map(([name, { type }]) => ({
      name,
      type: convertNetworkEnvironmentType(type)
    }));
  }
  async getNetworkInterfaces() {
    const network = this.owner.env.get(import_general.Network);
    const interfaces = await network.getNetInterfaces(this.networkInterfaceConfiguration);
    const interfaceDetails = new Array();
    for (const { name, type } of interfaces) {
      const details = await network.getIpMac(name);
      if (details !== void 0) {
        interfaceDetails.push({ name, type, ...details });
      }
    }
    return interfaceDetails;
  }
  openAdvertisementWindow() {
    return this.owner.env.get(import_protocol.DeviceAdvertiser).startAdvertising();
  }
  advertiseNow() {
    return this.owner.env.get(import_protocol.DeviceAdvertiser).advertise(true);
  }
  /**
   * A BLE broadcaster.
   */
  get bleBroadcaster() {
    if (this.#bleBroadcaster === void 0) {
      const bleData = this.owner.state.commissioning.additionalBleAdvertisementData;
      this.#bleBroadcaster = import_protocol.Ble.get().getBleBroadcaster(bleData);
    }
    return this.#bleBroadcaster;
  }
  /**
   * A BLE transport.
   */
  get bleTransport() {
    if (this.#bleTransport === void 0) {
      this.#bleTransport = import_protocol.Ble.get().getBlePeripheralInterface();
    }
    return this.#bleTransport;
  }
  /**
   * Add transports to the {@link TransportInterfaceSet}.
   */
  async addTransports(interfaces) {
    const netconf = this.owner.state.network;
    const port = this.owner.state.network.port;
    const ipv6Intf = await import_general.UdpInterface.create(
      this.owner.env.get(import_general.Network),
      "udp6",
      port ? port : void 0,
      netconf.listeningAddressIpv6
    );
    interfaces.add(ipv6Intf);
    await this.owner.set({ network: { operationalPort: ipv6Intf.port } });
    if (netconf.ipv4) {
      interfaces.add(
        await import_general.UdpInterface.create(
          this.owner.env.get(import_general.Network),
          "udp4",
          netconf.port,
          netconf.listeningAddressIpv4
        )
      );
    }
    if (netconf.ble) {
      interfaces.add(this.bleTransport);
    }
  }
  /**
   * Add broadcasters to the {@link DeviceAdvertiser}.
   */
  async addBroadcasters(advertiser) {
    await advertiser.clearBroadcasters();
    const isCommissioned = !!this.#commissionedFabrics;
    let discoveryCapabilities = this.owner.state.network.discoveryCapabilities;
    if (isCommissioned) {
      discoveryCapabilities = { onIpNetwork: true };
    }
    if (discoveryCapabilities.onIpNetwork) {
      advertiser.addBroadcaster(this.mdnsBroadcaster);
    }
    if (discoveryCapabilities.ble) {
      advertiser.addBroadcaster(this.bleBroadcaster);
    }
  }
  /**
   * When the first Fabric gets added we need to enable MDNS broadcasting.
   */
  enableMdnsBroadcasting() {
    const advertiser = this.owner.env.get(import_protocol.DeviceAdvertiser);
    const mdnsBroadcaster = this.mdnsBroadcaster;
    if (!advertiser.hasBroadcaster(mdnsBroadcaster)) {
      advertiser.addBroadcaster(mdnsBroadcaster);
    }
  }
  /**
   * On commission we turn off bluetooth and join the IP network if we haven't already.
   *
   * On decommission we're destroyed so don't need to handle that case.
   */
  endUncommissionedMode() {
    this.enableMdnsBroadcasting();
    if (this.#bleBroadcaster) {
      this.owner.env.runtime.add(this.#removeBleBroadcaster(this.#bleBroadcaster));
      this.#bleBroadcaster = void 0;
    }
    if (this.#bleTransport) {
      this.owner.env.runtime.add(this.#removeBleTransport(this.#bleTransport));
      this.#bleTransport = void 0;
    }
  }
  async #removeBleBroadcaster(bleBroadcaster) {
    const advertiser = this.owner.env.get(import_protocol.DeviceAdvertiser);
    await advertiser.deleteBroadcaster(bleBroadcaster);
    await bleBroadcaster.close();
  }
  async #removeBleTransport(bleTransport) {
    const transportInterfaces = this.owner.env.get(import_general.TransportInterfaceSet);
    transportInterfaces.delete(bleTransport);
    await bleTransport.close();
  }
  /**
   * Expose the internal InteractionServer for testing.
   */
  get interactionServer() {
    if (this.#interactionServer === void 0) {
      throw new import_general.ImplementationError("Interaction server is not available yet");
    }
    return this.#interactionServer;
  }
  get #commissionedFabrics() {
    return this.owner.state.operationalCredentials.commissionedFabrics;
  }
  endCommissioning() {
    return this.owner.env.get(import_protocol.DeviceCommissioner).endCommissioning();
  }
  async start() {
    const { owner } = this;
    const { env } = owner;
    await env.load(import_protocol.MdnsService);
    await this.addTransports(env.get(import_general.TransportInterfaceSet));
    await this.addBroadcasters(env.get(import_protocol.DeviceAdvertiser));
    await owner.act("start-network", (agent) => agent.load(import_ProductDescriptionServer.ProductDescriptionServer));
    env.get(import_protocol.ChannelManager).caseSessionsPerFabricAndNode = // Note that this is "sessions per fabric and node", so we support more than indicated by capabilityMinima
    owner.state.basicInformation.capabilityMinima.caseSessionsPerFabric;
    env.get(import_protocol.SessionManager).sessionParameters = {
      maxPathsPerInvoke: this.owner.state.basicInformation.maxPathsPerInvoke
    };
    this.#interactionServer = await import_TransactionalInteractionServer.TransactionalInteractionServer.create(this.owner, env.get(import_protocol.SessionManager));
    env.get(import_protocol.ExchangeManager).addProtocolHandler(this.#interactionServer);
    await this.owner.act("load-sessions", (agent) => agent.load(import_SessionsBehavior.SessionsBehavior));
    this.#observers.on(this.owner.eventsOf(import_CommissioningServer.CommissioningServer).commissioned, this.endUncommissionedMode);
    if (!env.has(import_protocol.CommissioningConfigProvider)) {
      if (owner.state.commissioning.enabled === void 0) {
        await owner.set({
          commissioning: { enabled: true }
        });
      }
      env.set(
        import_protocol.CommissioningConfigProvider,
        new class extends import_protocol.CommissioningConfigProvider {
          get values() {
            const config = {
              ...owner.state.commissioning,
              productDescription: owner.state.productDescription,
              ble: !!owner.state.network.ble
            };
            return config;
          }
        }()
      );
    }
    await this.configureCommissioning();
    this.#observers.on(this.owner.eventsOf(import_CommissioningServer.CommissioningServer).enabled$Changed, this.configureCommissioning);
    await this.openAdvertisementWindow();
  }
  async stop() {
    this.#observers.close();
    await this.owner.env.close(import_protocol.DeviceCommissioner);
    await this.owner.env.close(import_protocol.DeviceAdvertiser);
    await this.owner.env.close(import_protocol.ExchangeManager);
    await this.owner.env.close(import_protocol.SecureChannelProtocol);
    await this.owner.env.close(import_general.TransportInterfaceSet);
    await this.#interactionServer?.[Symbol.asyncDispose]();
    this.#interactionServer = void 0;
  }
  blockNewActivity() {
    this.#interactionServer?.blockNewActivity();
  }
  async configureCommissioning() {
    if (this.owner.state.commissioning.enabled) {
      this.owner.env.get(import_protocol.DeviceCommissioner);
    } else if (this.owner.env.has(import_protocol.DeviceCommissioner)) {
      await this.owner.env.close(import_protocol.DeviceCommissioner);
    }
  }
}
//# sourceMappingURL=ServerNetworkRuntime.js.map
