"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
var __typeError = (msg) => {
  throw TypeError(msg);
};
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 __using = (stack, value, async) => {
  if (value != null) {
    if (typeof value !== "object" && typeof value !== "function") __typeError("Object expected");
    var dispose, inner;
    if (async) dispose = value[__knownSymbol("asyncDispose")];
    if (dispose === void 0) {
      dispose = value[__knownSymbol("dispose")];
      if (async) inner = dispose;
    }
    if (typeof dispose !== "function") __typeError("Object not disposable");
    if (inner) dispose = function() {
      try {
        inner.call(this);
      } catch (e) {
        return Promise.reject(e);
      }
    };
    stack.push([async, dispose, value]);
  } else if (async) {
    stack.push([async]);
  }
  return value;
};
var __callDispose = (stack, error, hasError) => {
  var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
    return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
  };
  var fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e);
  var next = (it) => {
    while (it = stack.pop()) {
      try {
        var result = it[1] && it[1].call(it[2]);
        if (it[0]) return Promise.resolve(result).then(next, (e) => (fail(e), next()));
      } catch (e) {
        fail(e);
      }
    }
    if (hasError) throw error;
  };
  return next();
};
var AdministratorCommissioningServer_exports = {};
__export(AdministratorCommissioningServer_exports, {
  AdministratorCommissioningServer: () => AdministratorCommissioningServer
});
module.exports = __toCommonJS(AdministratorCommissioningServer_exports);
var import_general = require("@matter/general");
var import_protocol = require("@matter/protocol");
var import_types = require("@matter/types");
var import_administrator_commissioning = require("@matter/types/clusters/administrator-commissioning");
var import_AdministratorCommissioningBehavior = require("./AdministratorCommissioningBehavior.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const openCommissioningWindow = import_administrator_commissioning.AdministratorCommissioning.schema.commands.require("OpenCommissioningWindow");
const AdministratorCommissioningSchema = import_administrator_commissioning.AdministratorCommissioning.schema.extend(
  void 0,
  openCommissioningWindow.extend(
    void 0,
    openCommissioningWindow.fields.extend("PakePasscodeVerifier", { constraint: "none" }),
    openCommissioningWindow.fields.extend("Iterations", { constraint: "none" }),
    openCommissioningWindow.fields.extend("Salt", { constraint: "none" })
  )
);
const AdministratorCommissioningBase = import_AdministratorCommissioningBehavior.AdministratorCommissioningBehavior.for(
  import_administrator_commissioning.AdministratorCommissioning,
  AdministratorCommissioningSchema
);
const logger = import_general.Logger.get("AdministratorCommissioningServer");
class AdministratorCommissioningServer extends AdministratorCommissioningBase {
  static lockOnInvoke = false;
  /**
   * This method opens an Enhanced Commissioning Window (a dynamic passcode is used which was provided by the caller).
   */
  async openCommissioningWindow({
    pakePasscodeVerifier,
    discriminator,
    iterations,
    salt,
    commissioningTimeout
  }) {
    if (pakePasscodeVerifier.byteLength !== import_types.PAKE_PASSCODE_VERIFIER_LENGTH) {
      throw new import_administrator_commissioning.AdministratorCommissioning.PakeParameterError("PAKE passcode verifier length is invalid");
    }
    if (iterations < 1e3 || iterations > 1e5) {
      throw new import_administrator_commissioning.AdministratorCommissioning.PakeParameterError("PAKE iterations invalid");
    }
    if (salt.byteLength < 16 || salt.byteLength > 32) {
      throw new import_administrator_commissioning.AdministratorCommissioning.PakeParameterError("PAKE salt has invalid length.");
    }
    const commissioner = this.env.get(import_protocol.DeviceCommissioner);
    const timeout = (0, import_general.Seconds)(commissioningTimeout);
    this.#assertCommissioningWindowRequirements(timeout, commissioner);
    this.#initializeCommissioningWindow(
      timeout,
      import_administrator_commissioning.AdministratorCommissioning.CommissioningWindowStatus.EnhancedWindowOpen
    );
    await this.env.get(import_protocol.DeviceCommissioner).allowEnhancedCommissioning(
      discriminator,
      import_protocol.PaseServer.fromVerificationValue(this.env.get(import_protocol.SessionManager), pakePasscodeVerifier, {
        iterations,
        salt
      }),
      this.callback(this.#endCommissioning)
    );
  }
  /** This method opens a Basic Commissioning Window. The default passcode is used. */
  async openBasicCommissioningWindow({
    commissioningTimeout
  }) {
    const commissioner = this.env.get(import_protocol.DeviceCommissioner);
    const timeout = (0, import_general.Seconds)(commissioningTimeout);
    this.#assertCommissioningWindowRequirements(timeout, commissioner);
    this.#initializeCommissioningWindow(
      timeout,
      import_administrator_commissioning.AdministratorCommissioning.CommissioningWindowStatus.BasicWindowOpen
    );
    await commissioner.allowBasicCommissioning(this.callback(this.#endCommissioning));
  }
  /**
   * This method is used to revoke a commissioning window.
   *
   * Spec 1.5.1 requires Step 1 cleanup to run regardless of window state before checking the window.
   */
  async revokeCommissioning() {
    logger.debug("Revoking commissioning window");
    const paseSession = this.env.get(import_protocol.SessionManager).getPaseSession();
    if (paseSession) {
      await paseSession.initiateClose();
    }
    if (this.env.has(import_protocol.FailsafeContext)) {
      const failsafeContext = this.env.get(import_protocol.FailsafeContext);
      if (failsafeContext) {
        await failsafeContext.close(this.context.exchange);
      }
    }
    if (this.internal.commissioningWindowTimeout === void 0) {
      throw new import_administrator_commissioning.AdministratorCommissioning.WindowNotOpenError(
        "No commissioning window is opened that could be revoked."
      );
    }
    await this.#closeCommissioningWindow();
  }
  /**
   * Called whenever a Commissioning/Announcement Window is opened by this cluster. This method starts the timer and
   * adjusts the needed attributes.
   */
  #initializeCommissioningWindow(commissioningTimeout, windowStatus) {
    if (this.internal.commissioningWindowTimeout !== void 0) {
      throw new import_general.InternalError("Commissioning window already initialized.");
    }
    const actor = (0, import_protocol.hasRemoteActor)(this.context) ? this.context.session.via : "local actor";
    logger.debug(`Commissioning window timer started for ${commissioningTimeout} seconds for ${actor}.`);
    this.internal.commissioningWindowTimeout = import_general.Time.getTimer(
      "Commissioning timeout",
      commissioningTimeout,
      this.callback(this.#commissioningTimeout)
    ).start();
    (0, import_protocol.assertRemoteActor)(this.context);
    const adminFabric = this.context.session.associatedFabric;
    this.state.windowStatus = windowStatus;
    this.state.adminFabricIndex = adminFabric.fabricIndex;
    this.state.adminVendorId = adminFabric.rootVendorId;
    const removeCallback = this.callback(this.#fabricRemovedCallback);
    this.internal.stopMonitoringFabricForRemoval = () => {
      adminFabric.deleting.off(removeCallback);
    };
    this.context.session.associatedFabric.deleting.on(removeCallback);
  }
  /**
   * This method validates if a commissioning window can be opened and throws various exceptions in case of failures.
   */
  #assertCommissioningWindowRequirements(commissioningTimeout, commissioner) {
    if (this.internal.commissioningWindowTimeout !== void 0) {
      throw new import_administrator_commissioning.AdministratorCommissioning.BusyError("A commissioning window is already opened");
    }
    if (commissioningTimeout > this.internal.maximumCommissioningTimeout) {
      throw new import_types.StatusResponseError(
        `Commissioning timeout must not exceed ${this.internal.maximumCommissioningTimeout} seconds.`,
        import_types.Status.InvalidCommand
      );
    }
    if (commissioningTimeout < this.internal.minimumCommissioningTimeout) {
      throw new import_types.StatusResponseError(
        `Commissioning timeout must not be lower then ${this.internal.minimumCommissioningTimeout} seconds.`,
        import_types.Status.InvalidCommand
      );
    }
    if (commissioner.isFailsafeArmed) {
      throw new import_administrator_commissioning.AdministratorCommissioning.BusyError("Failsafe timer armed, assume commissioning in progress.");
    }
  }
  /**
   * This method is used internally when the commissioning window timer expires or the commissioning was completed.
   */
  #endCommissioning() {
    logger.debug("Ending commissioning");
    if (this.internal.commissioningWindowTimeout !== void 0) {
      this.internal.commissioningWindowTimeout.stop();
      this.internal.commissioningWindowTimeout = void 0;
    }
    this.internal.stopMonitoringFabricForRemoval?.();
    this.state.adminFabricIndex = null;
    this.state.windowStatus = import_administrator_commissioning.AdministratorCommissioning.CommissioningWindowStatus.WindowNotOpen;
    this.state.adminFabricIndex = null;
    this.state.adminVendorId = null;
  }
  /**
   * Closes the commissioning window per the matter specification.
   */
  async #closeCommissioningWindow() {
    var _stack = [];
    try {
      const _closing = __using(_stack, this.lifetime.join("closing commissioning window"));
      await this.env.get(import_protocol.DeviceCommissioner).endCommissioning();
    } catch (_) {
      var _error = _, _hasError = true;
    } finally {
      __callDispose(_stack, _error, _hasError);
    }
  }
  /**
   * Close commissioning window on timeout when there's nobody to await the resulting promise
   * */
  #commissioningTimeout() {
    this.env.runtime.add(
      (0, import_general.Worker)({
        name: "closing commissioning window",
        done: this.#closeCommissioningWindow()
      })
    );
  }
  /**
   * Invoked when fabric is removed.
   */
  #fabricRemovedCallback() {
    this.state.adminFabricIndex = null;
    this.internal.stopMonitoringFabricForRemoval?.();
  }
  /**
   * Clean up resources and stop the timer when the behavior is destroyed.
   */
  [Symbol.asyncDispose]() {
    if (this.internal.commissioningWindowTimeout !== void 0) {
      this.internal.commissioningWindowTimeout.stop();
      this.internal.commissioningWindowTimeout = void 0;
    }
  }
}
((AdministratorCommissioningServer2) => {
  class Internal {
    commissioningWindowTimeout;
    stopMonitoringFabricForRemoval;
    /**
     * Mandated by spec; should only be modified in testing.
     */
    minimumCommissioningTimeout = import_types.MINIMUM_COMMISSIONING_TIMEOUT;
    /**
     * Commissioning beyond the standard 15-minute window is "extended commissioning" and has limitations on
     * advertisement.  We default to the standard window.
     */
    maximumCommissioningTimeout = import_types.STANDARD_COMMISSIONING_TIMEOUT;
  }
  AdministratorCommissioningServer2.Internal = Internal;
  class State extends AdministratorCommissioningBase.State {
    // Spec doesn't declare a default here so set manually
    windowStatus = import_administrator_commissioning.AdministratorCommissioning.CommissioningWindowStatus.WindowNotOpen;
  }
  AdministratorCommissioningServer2.State = State;
})(AdministratorCommissioningServer || (AdministratorCommissioningServer = {}));
//# sourceMappingURL=AdministratorCommissioningServer.js.map
