"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 NetworkProfile_exports = {};
__export(NetworkProfile_exports, {
  NetworkProfiles: () => NetworkProfiles,
  UnknownNetworkProfileError: () => UnknownNetworkProfileError
});
module.exports = __toCommonJS(NetworkProfile_exports);
var import_PeerAddress = require("#peer/PeerAddress.js");
var import_general = require("@matter/general");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("NetworkProfiles");
class UnknownNetworkProfileError extends import_general.MatterError {
}
class NetworkProfiles {
  #networks = /* @__PURE__ */ new Map();
  #defaults;
  constructor(options) {
    this.#defaults = {
      ...NetworkProfiles.defaults,
      ...options
    };
  }
  set defaults(options) {
    const base = { ...NetworkProfiles.defaults };
    for (const key of Object.keys(options)) {
      const override = options[key];
      if (override !== void 0) {
        const { connect, probeAddress, ...rest } = override;
        const merged = (0, import_general.merge)(base[key], rest);
        if (connect !== void 0) {
          merged.connect = (0, import_general.merge)(base[key].connect ?? {}, connect);
        }
        if (probeAddress !== void 0) {
          merged.probeAddress = (0, import_general.merge)(
            base[key].probeAddress ?? {},
            probeAddress
          );
        }
        base[key] = merged;
      }
    }
    this.#defaults = base;
  }
  static [import_general.Environmental.create](env) {
    const instance = new this();
    env.set(NetworkProfiles, instance);
    return instance;
  }
  select(peer, id) {
    if (id !== void 0) {
      return this.get(id);
    }
    return this.forPeer(peer);
  }
  /**
   * Retrieve the named network profile.
   *
   * @param id one of the standard {@link NetworkProfiles.Templates} or any previously configured identifier
   */
  get(id) {
    const network = this.#networks.get(id);
    if (network) {
      return network;
    }
    if (!(id in NetworkProfiles.defaults)) {
      throw new UnknownNetworkProfileError(`Network profile ${id} is not configured`);
    }
    return this.configure(id, NetworkProfiles.defaults[id]);
  }
  configure(id, limits) {
    const network = {
      id,
      semaphore: new import_general.Semaphore(`network semaphore ${id}`, limits.exchanges, limits.delay, limits.timeout)
    };
    if (limits.connect) {
      network.connect = this.configure(`${id}:connect`, {
        ...limits.connect,
        connect: void 0,
        probeAddress: void 0
      });
    }
    if (limits.probeAddress) {
      network.probeAddress = this.configure(`${id}:probe`, {
        ...limits.probeAddress,
        connect: void 0,
        probeAddress: void 0
      });
    }
    logger.info(
      "Configure profile",
      id,
      import_general.Diagnostic.dict({ ...limits, connect: void 0, probeAddress: void 0 })
    );
    this.#networks.set(id, network);
    return network;
  }
  forPeer(peer) {
    const pp = peer.physicalProperties;
    let id, defaults;
    if (import_PeerAddress.PeerAddress.isGroup(peer.address)) {
      id = "group";
      defaults = this.#defaults.fast;
    } else if (pp === void 0) {
      id = "unknown";
      defaults = this.#defaults.unknown;
    } else if (pp.threadActive || pp.threadActive === void 0 && pp.supportsThread) {
      if (pp.threadChannel) {
        id = `thread:${pp.threadChannel}`;
      } else {
        id = "thread";
      }
      defaults = this.#defaults.thread;
    } else if (pp.supportsWifi || pp.supportsEthernet || // We have data but no Network Commissioning cluster, means "other means"
    !pp.supportsWifi && !pp.supportsEthernet && !pp.supportsThread && pp.rootEndpointServerList.length > 0) {
      id = "fast";
      defaults = this.#defaults.fast;
    } else {
      id = "unknown";
      defaults = this.#defaults.unknown;
    }
    return this.#networks.get(id) ?? this.configure(id, defaults);
  }
}
((NetworkProfiles2) => {
  NetworkProfiles2.conservative = {
    exchanges: 4,
    delay: (0, import_general.Millis)(100),
    connect: {
      exchanges: 4,
      timeout: (0, import_general.Seconds)(10)
      // Release slot for connections after 15s latest
    },
    probeAddress: {
      exchanges: 2,
      timeout: (0, import_general.Seconds)(15)
    }
  };
  NetworkProfiles2.defaults = {
    unlimited: { exchanges: Infinity },
    fast: { exchanges: 200 },
    thread: NetworkProfiles2.conservative,
    conservative: NetworkProfiles2.conservative,
    unknown: NetworkProfiles2.conservative
  };
})(NetworkProfiles || (NetworkProfiles = {}));
//# sourceMappingURL=NetworkProfile.js.map
