"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 AdministratorCommissioningServer_exports = {};
__export(AdministratorCommissioningServer_exports, {
  AdministratorCommissioningServer: () => AdministratorCommissioningServer
});
module.exports = __toCommonJS(AdministratorCommissioningServer_exports);
var import_administrator_commissioning = require("#clusters/administrator-commissioning");
var import_general = require("#general");
var import_model = require("#model");
var import_protocol = require("#protocol");
var import_types = require("#types");
var import_AdministratorCommissioningBehavior = require("./AdministratorCommissioningBehavior.js");
/**
 * @license
 * Copyright 2022-2024 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import_administrator_commissioning.AdministratorCommissioning.Cluster.commands = {
  ...import_administrator_commissioning.AdministratorCommissioning.Cluster.commands,
  openCommissioningWindow: (0, import_types.Command)(
    0,
    (0, import_types.TlvObject)({
      commissioningTimeout: (0, import_types.TlvField)(0, import_types.TlvUInt16),
      pakePasscodeVerifier: (0, import_types.TlvField)(1, import_types.TlvByteString),
      discriminator: (0, import_types.TlvField)(2, import_types.TlvUInt16.bound({ max: 4095 })),
      iterations: (0, import_types.TlvField)(3, import_types.TlvUInt32),
      salt: (0, import_types.TlvField)(4, import_types.TlvByteString)
    }),
    0,
    import_types.TlvNoResponse,
    {
      invokeAcl: import_model.AccessLevel.Administer,
      timed: true
    }
  )
};
const logger = import_general.Logger.get("AdministratorCommissioningServer");
class AdministratorCommissioningServer extends import_AdministratorCommissioningBehavior.AdministratorCommissioningBehavior {
  /**
   * 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.length !== import_types.PAKE_PASSCODE_VERIFIER_LENGTH) {
      throw new import_types.StatusResponseError(
        "PAKE Passcode verifier length is invalid.",
        import_types.StatusCode.Failure,
        import_administrator_commissioning.AdministratorCommissioning.StatusCode.PakeParameterError
      );
    }
    if (iterations < 1e3 || iterations > 1e5) {
      throw new import_types.StatusResponseError(
        "PAKE iterations invalid.",
        import_types.StatusCode.Failure,
        import_administrator_commissioning.AdministratorCommissioning.StatusCode.PakeParameterError
      );
    }
    if (salt.length < 16 || salt.length > 32) {
      throw new import_types.StatusResponseError(
        "PAKE salt has invalid length.",
        import_types.StatusCode.Failure,
        import_administrator_commissioning.AdministratorCommissioning.StatusCode.PakeParameterError
      );
    }
    const commissioner = this.env.get(import_protocol.DeviceCommissioner);
    this.#assertCommissioningWindowRequirements(commissioningTimeout, commissioner);
    this.#initializeCommissioningWindow(
      commissioningTimeout,
      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);
    this.#assertCommissioningWindowRequirements(commissioningTimeout, commissioner);
    this.#initializeCommissioningWindow(
      commissioningTimeout,
      import_administrator_commissioning.AdministratorCommissioning.CommissioningWindowStatus.BasicWindowOpen
    );
    await commissioner.allowBasicCommissioning(this.callback(this.#endCommissioning));
  }
  /** This method is used to revoke a commissioning window. */
  async revokeCommissioning() {
    if (this.internal.commissioningWindowTimeout === void 0) {
      throw new import_types.StatusResponseError(
        "No commissioning window is opened that could be revoked.",
        import_types.StatusCode.Failure,
        import_administrator_commissioning.AdministratorCommissioning.StatusCode.WindowNotOpen
      );
    }
    logger.debug("Revoking commissioning window.");
    await this.#closeCommissioningWindow();
    if (this.env.has(import_protocol.FailsafeContext)) {
      const failsafeContext = this.env.get(import_protocol.FailsafeContext);
      if (failsafeContext) {
        await failsafeContext.close();
      }
    }
  }
  /**
   * 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.");
    }
    logger.debug(
      `Commissioning window timer started for ${commissioningTimeout} seconds for ${this.context.session?.name}.`
    );
    this.internal.commissioningWindowTimeout = import_general.Time.getTimer(
      "Commissioning timeout",
      commissioningTimeout * 1e3,
      this.callback(this.#commissioningTimeout)
    ).start();
    const adminFabric = this.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.deleteRemoveCallback(removeCallback);
    };
    this.session.associatedFabric.addRemoveCallback(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_types.StatusResponseError(
        "A commissioning window is already opened.",
        import_types.StatusCode.Failure,
        import_administrator_commissioning.AdministratorCommissioning.StatusCode.Busy
      );
    }
    if (commissioningTimeout > import_types.MAXIMUM_COMMISSIONING_TIMEOUT_S) {
      throw new import_types.StatusResponseError(
        `Commissioning timeout must not exceed ${import_types.MAXIMUM_COMMISSIONING_TIMEOUT_S} seconds.`,
        import_types.StatusCode.InvalidCommand
      );
    }
    if (commissioningTimeout < import_types.MINIMUM_COMMISSIONING_TIMEOUT_S) {
      throw new import_types.StatusResponseError(
        `Commissioning timeout must not be lower then ${import_types.MINIMUM_COMMISSIONING_TIMEOUT_S} seconds.`,
        import_types.StatusCode.InvalidCommand
      );
    }
    if (commissioner.isFailsafeArmed) {
      throw new import_types.StatusResponseError(
        "Failsafe timer armed, assume commissioning in progress.",
        import_types.StatusCode.Failure,
        import_administrator_commissioning.AdministratorCommissioning.StatusCode.Busy
      );
    }
  }
  /**
   * This method is used internally when the commissioning window timer expires or the commissioning was completed.
   */
  #endCommissioning() {
    logger.debug("End commissioning window.");
    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() {
    this.callback(this.#endCommissioning);
    await this.env.get(import_protocol.DeviceCommissioner).endCommissioning();
  }
  /**
   * Close commissioning window on timeout when there's nobody to await the resulting promise
   * */
  #commissioningTimeout() {
    this.env.runtime.add(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;
  }
  AdministratorCommissioningServer2.Internal = Internal;
  class State extends import_AdministratorCommissioningBehavior.AdministratorCommissioningBehavior.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
