"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
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 AccessControl_exports = {};
__export(AccessControl_exports, {
  AccessControlAPI: () => AccessControlAPI
});
module.exports = __toCommonJS(AccessControl_exports);
var import_cc = require("@zwave-js/cc");
var import_UserCodeCC = require("@zwave-js/cc/UserCodeCC");
var import_UserCredentialCC = require("@zwave-js/cc/UserCredentialCC");
var import_core = require("@zwave-js/core");
var import_shared = require("@zwave-js/shared");
var import_FeatureAPI = require("./FeatureAPI.js");
const NON_PIN_CHARS = /[^0-9]/;
function supportsNonPINChars(supportedASCIIChars) {
  return supportedASCIIChars != void 0 && NON_PIN_CHARS.test(supportedASCIIChars);
}
__name(supportsNonPINChars, "supportsNonPINChars");
class AccessControlAPI extends import_FeatureAPI.FeatureAPI {
  static {
    __name(this, "AccessControlAPI");
  }
  // FIXME: This is technically not correct. A node could support both CCs,
  // and we may have to decide which one to use, or switch between them on
  // the fly using Version CC / migration.
  // This is not implemented yet, so checking for U3C first is fine for now.
  get #usesUserCredentialCC() {
    return this.endpoint.supportsCC(import_core.CommandClasses["User Credential"]);
  }
  /**
   * Returns the user-related capabilities of this endpoint.
   * This method uses cached information from the most recent interview.
   */
  getUserCapabilitiesCached() {
    if (this.#usesUserCredentialCC) {
      return {
        maxUsers: this.getValue(import_UserCredentialCC.UserCredentialCCValues.supportedUsers.endpoint(this.endpoint.index)) ?? 0,
        supportedUserTypes: this.getValue(import_UserCredentialCC.UserCredentialCCValues.supportedUserTypes.endpoint(this.endpoint.index)) ?? [],
        maxUserNameLength: this.getValue(import_UserCredentialCC.UserCredentialCCValues.maxUserNameLength.endpoint(this.endpoint.index)) ?? void 0,
        supportedCredentialRules: this.getValue(import_UserCredentialCC.UserCredentialCCValues.supportedCredentialRules.endpoint(this.endpoint.index)) ?? []
      };
    } else {
      const supportedStatuses = this.getValue(import_UserCodeCC.UserCodeCCValues.supportedUserIDStatuses.endpoint(this.endpoint.index)) ?? [];
      const supportedUserTypes = [
        import_cc.UserCredentialUserType.General
      ];
      if (supportedStatuses.includes(import_cc.UserIDStatus.Messaging)) {
        supportedUserTypes.push(import_cc.UserCredentialUserType.NonAccess);
      }
      return {
        maxUsers: this.getValue(import_UserCodeCC.UserCodeCCValues.supportedUsers.endpoint(this.endpoint.index)) ?? 0,
        supportedUserTypes,
        // User Code CC does not support user names or credential rules
        maxUserNameLength: void 0,
        supportedCredentialRules: [import_cc.UserCredentialRule.Single]
      };
    }
  }
  /**
   * Returns the credential-related capabilities of this endpoint.
   * This method uses cached information from the most recent interview.
   */
  getCredentialCapabilitiesCached() {
    if (this.#usesUserCredentialCC) {
      const supportedTypes = this.getValue(import_UserCredentialCC.UserCredentialCCValues.supportedCredentialTypes.endpoint(this.endpoint.index)) ?? [];
      const credentialTypes = /* @__PURE__ */ new Map();
      for (const type of supportedTypes) {
        const cap = this.getValue(import_UserCredentialCC.UserCredentialCCValues.credentialCapabilities(type).endpoint(this.endpoint.index));
        if (cap)
          credentialTypes.set(type, cap);
      }
      return {
        supportedCredentialTypes: credentialTypes,
        supportsAdminCode: this.getValue(import_UserCredentialCC.UserCredentialCCValues.supportsAdminCode.endpoint(this.endpoint.index)) ?? false,
        supportsAdminCodeDeactivation: this.getValue(import_UserCredentialCC.UserCredentialCCValues.supportsAdminCodeDeactivation.endpoint(this.endpoint.index)) ?? false
      };
    } else {
      const credentialTypes = /* @__PURE__ */ new Map();
      credentialTypes.set(this.#ucCredentialType, {
        numberOfCredentialSlots: 1,
        minCredentialLength: 4,
        maxCredentialLength: 10,
        maxCredentialHashLength: 0,
        supportsCredentialLearn: false
      });
      return {
        supportedCredentialTypes: credentialTypes,
        supportsAdminCode: this.getValue(import_UserCodeCC.UserCodeCCValues.supportsAdminCode.endpoint(this.endpoint.index)) ?? false,
        supportsAdminCodeDeactivation: this.getValue(import_UserCodeCC.UserCodeCCValues.supportsAdminCodeDeactivation.endpoint(this.endpoint.index)) ?? false
      };
    }
  }
  /**
   * Returns the data for the user with the given ID.
   * This communicates with the node to retrieve fresh information.
   */
  async getUser(userId) {
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      const result = await api.getUser(userId);
      if (!result?.userId)
        return void 0;
      return {
        userId: result.userId,
        active: result.active ?? false,
        userType: result.userType ?? import_cc.UserCredentialUserType.General,
        userName: result.userName ?? void 0,
        credentialRule: result.credentialRule ?? void 0,
        expiringTimeoutMinutes: result.expiringTimeoutMinutes || void 0
      };
    } else {
      const api = this.#ucAPI();
      const result = await api.get(userId);
      if (!result)
        return void 0;
      return this.#mapUserCodeStatusToUserData(userId, result.userIdStatus);
    }
  }
  /**
   * Returns the data for the user with the given ID.
   * This method uses cached information from the most recent interview.
   */
  getUserCached(userId) {
    if (this.#usesUserCredentialCC) {
      return this.#getUserCached_U3C(userId);
    } else {
      return this.#getUserCached_UC(userId);
    }
  }
  /**
   * Returns the data for all configured users.
   * This communicates with the node to retrieve fresh information.
   */
  async getUsers() {
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      const users = [];
      let nextUserId = 0;
      do {
        const result = await api.getUser(nextUserId);
        if (!result?.userId)
          break;
        users.push({
          userId: result.userId,
          active: result.active ?? false,
          userType: result.userType ?? import_cc.UserCredentialUserType.General,
          userName: result.userName ?? void 0,
          credentialRule: result.credentialRule ?? void 0,
          expiringTimeoutMinutes: result.expiringTimeoutMinutes || void 0
        });
        nextUserId = result.nextUserId;
      } while (nextUserId > 0);
      return users;
    } else {
      const api = this.#ucAPI();
      const maxUsers = await api.getUsersCount();
      if (!maxUsers)
        return [];
      const users = [];
      const supportsBulk = !!this.getValue(import_UserCodeCC.UserCodeCCValues.supportsMultipleUserCodeReport.endpoint(this.endpoint.index));
      if (supportsBulk) {
        let nextUserId = 1;
        while (nextUserId > 0 && nextUserId <= maxUsers) {
          const response = await api.get(nextUserId, true);
          if (!response)
            break;
          users.push(...response.userCodes.map((entry) => this.#mapUserCodeStatusToUserData(entry.userId, entry.userIdStatus)).filter((u) => u != void 0));
          nextUserId = response.nextUserId;
        }
      } else {
        for (let userId = 1; userId <= maxUsers; userId++) {
          const result = await api.get(userId);
          if (!result)
            continue;
          const user = this.#mapUserCodeStatusToUserData(userId, result.userIdStatus);
          if (user)
            users.push(user);
        }
      }
      return users;
    }
  }
  /**
   * Returns the data for all configured users.
   * This method uses cached information from the most recent interview.
   */
  getUsersCached() {
    if (this.#usesUserCredentialCC) {
      const maxUsers = this.getValue(import_UserCredentialCC.UserCredentialCCValues.supportedUsers.endpoint(this.endpoint.index)) ?? 0;
      const users = [];
      for (let userId = 1; userId <= maxUsers; userId++) {
        const user = this.#getUserCached_U3C(userId);
        if (user)
          users.push(user);
      }
      return users;
    } else {
      const maxUsers = this.getValue(import_UserCodeCC.UserCodeCCValues.supportedUsers.endpoint(this.endpoint.index)) ?? 0;
      const users = [];
      for (let userId = 1; userId <= maxUsers; userId++) {
        const user = this.#getUserCached_UC(userId);
        if (user)
          users.push(user);
      }
      return users;
    }
  }
  /**
   * Creates or updates the user with the given ID.
   * This communicates with the node.
   */
  async setUser(userId, options) {
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      const existing = this.#getUserCached_U3C(userId);
      const operationType = existing ? import_cc.UserCredentialOperationType.Modify : import_cc.UserCredentialOperationType.Add;
      const userType = options.userType ?? existing?.userType ?? import_cc.UserCredentialUserType.General;
      if (userType === import_cc.UserCredentialUserType.Expiring) {
        return api.setUser({
          operationType,
          userId,
          active: options.active ?? existing?.active ?? true,
          userType,
          expiringTimeoutMinutes: options.expiringTimeoutMinutes ?? existing?.expiringTimeoutMinutes ?? 0,
          credentialRule: options.credentialRule ?? existing?.credentialRule,
          userName: options.userName ?? existing?.userName
        });
      }
      return api.setUser({
        operationType,
        userId,
        active: options.active ?? existing?.active ?? true,
        userType,
        credentialRule: options.credentialRule ?? existing?.credentialRule,
        userName: options.userName ?? existing?.userName
      });
    } else {
      const api = this.#ucAPI();
      const existing = this.#getUserCached_UC(userId);
      const existingStatus = this.getValue(import_UserCodeCC.UserCodeCCValues.userIdStatus(userId).endpoint(this.endpoint.index));
      const active = options.active ?? existing?.active ?? true;
      const userType = options.userType ?? existing?.userType ?? import_cc.UserCredentialUserType.General;
      let status;
      if (!active) {
        status = import_cc.UserIDStatus.Disabled;
      } else if (userType === import_cc.UserCredentialUserType.NonAccess) {
        status = import_cc.UserIDStatus.Messaging;
      } else {
        status = import_cc.UserIDStatus.Enabled;
      }
      const existingCode = this.getValue(import_UserCodeCC.UserCodeCCValues.userCode(userId).endpoint(this.endpoint.index));
      if (!existingCode) {
        throw new import_core.ZWaveError("User Code CC requires a credential to be set before modifying the user. Use setCredential() first.", import_core.ZWaveErrorCodes.Argument_Invalid);
      }
      const result = await api.set(userId, status, existingCode);
      let succeeded;
      if (result == void 0) {
        const verified = await api.get(userId);
        const verifiedStatus = verified?.userIdStatus;
        succeeded = verifiedStatus != void 0 && verifiedStatus !== existingStatus && verifiedStatus !== import_cc.UserIDStatus.Available;
      } else {
        succeeded = (0, import_core.supervisedCommandSucceeded)(result);
      }
      if (succeeded) {
        const node = this.endpoint.tryGetNode();
        if (node) {
          const userData = { userId, active, userType };
          node.emit(existing ? "user modified" : "user added", this.endpoint, userData);
        }
      }
      return result;
    }
  }
  /**
   * Deletes the user with the given ID and all of their credentials.
   * This communicates with the node.
   */
  async deleteUser(userId) {
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      const result = await api.setUser({
        operationType: import_cc.UserCredentialOperationType.Delete,
        userId
      });
      if ((0, import_core.isUnsupervisedOrSucceeded)(result)) {
        this.#purgeCachedCredentials(userId);
      }
      return result;
    } else {
      const existed = this.#getUserCached_UC(userId) != void 0;
      const api = this.#ucAPI();
      const result = await api.clear(userId);
      let succeeded;
      if (result == void 0) {
        const verified = await api.get(userId);
        succeeded = existed && verified?.userIdStatus === import_cc.UserIDStatus.Available;
      } else {
        succeeded = (0, import_core.supervisedCommandSucceeded)(result) && existed;
      }
      if (succeeded) {
        const node = this.endpoint.tryGetNode();
        if (node) {
          node.emit("user deleted", this.endpoint, { userId });
          node.emit("credential deleted", this.endpoint, {
            userId,
            credentialType: this.#ucCredentialType,
            credentialSlot: 1
          });
        }
      }
      return result;
    }
  }
  /**
   * Deletes all users and their credentials.
   * This communicates with the node.
   */
  async deleteAllUsers() {
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      const result = await api.setUser({
        operationType: import_cc.UserCredentialOperationType.Delete,
        userId: 0
      });
      if ((0, import_core.isUnsupervisedOrSucceeded)(result)) {
        this.#purgeAllCachedUsersAndCredentials();
      }
      return result;
    } else {
      const api = this.#ucAPI();
      const result = await api.clear(0);
      if ((0, import_core.isUnsupervisedOrSucceeded)(result)) {
        this.#purgeAllCachedUserCodes();
      }
      return result;
    }
  }
  /**
   * Returns the data for a specific credential.
   * This communicates with the node to retrieve fresh information.
   */
  async getCredential(userId, type, slot) {
    this.#assertValidSlot(type, slot);
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      const result = await api.getCredential(userId, type, slot);
      if (!result?.credentialSlot)
        return void 0;
      return {
        userId: result.userId,
        type: result.credentialType,
        slot: result.credentialSlot,
        data: result.credentialData
      };
    } else {
      const api = this.#ucAPI();
      const result = await api.get(userId);
      if (!result)
        return void 0;
      if (result.userIdStatus === import_cc.UserIDStatus.Available || result.userIdStatus === import_cc.UserIDStatus.StatusNotAvailable) {
        return void 0;
      }
      return { userId, type, slot, data: result.userCode };
    }
  }
  /**
   * Returns the data for a specific credential.
   * This method uses cached information from the most recent interview.
   */
  getCredentialCached(userId, type, slot) {
    this.#assertValidSlot(type, slot);
    if (this.#usesUserCredentialCC) {
      return this.#getCredentialCached_U3C(userId, type, slot);
    } else {
      return this.#getCredentialCached_UC(userId, type, slot);
    }
  }
  /**
   * Returns all credentials for the given user.
   * This communicates with the node to retrieve fresh information.
   */
  async getCredentials(userId) {
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      const credentials = [];
      let nextCredType = import_cc.UserCredentialType.None;
      let nextCredSlot = 0;
      do {
        const result = await api.getCredential(userId, nextCredType, nextCredSlot);
        if (!result?.credentialSlot)
          break;
        credentials.push({
          userId: result.userId,
          type: result.credentialType,
          slot: result.credentialSlot,
          data: result.credentialData
        });
        nextCredType = result.nextCredentialType;
        nextCredSlot = result.nextCredentialSlot;
      } while (nextCredType !== import_cc.UserCredentialType.None || nextCredSlot !== 0);
      return credentials;
    } else {
      const cred = await this.getCredential(userId, this.#ucCredentialType, 1);
      return cred ? [cred] : [];
    }
  }
  /**
   * Returns all credentials for the given user.
   * This method uses cached information from the most recent interview.
   */
  getCredentialsCached(userId) {
    if (this.#usesUserCredentialCC) {
      const credentials = [];
      const supportedTypes = this.getValue(import_UserCredentialCC.UserCredentialCCValues.supportedCredentialTypes.endpoint(this.endpoint.index)) ?? [];
      for (const type of supportedTypes) {
        const cap = this.getValue(import_UserCredentialCC.UserCredentialCCValues.credentialCapabilities(type).endpoint(this.endpoint.index));
        if (!cap)
          continue;
        for (let slot = 1; slot <= cap.numberOfCredentialSlots; slot++) {
          const cred = this.#getCredentialCached_U3C(userId, type, slot);
          if (cred)
            credentials.push(cred);
        }
      }
      return credentials;
    } else {
      const cred = this.#getCredentialCached_UC(userId, this.#ucCredentialType, 1);
      return cred ? [cred] : [];
    }
  }
  /**
   * Creates or updates a credential for the given user.
   * This communicates with the node.
   */
  async setCredential(userId, type, slot, data) {
    this.#assertValidSlot(type, slot);
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      const existing = this.#getCredentialCached_U3C(userId, type, slot);
      const credentialData = typeof data === "string" ? import_shared.Bytes.from(data, "utf-8") : import_shared.Bytes.from(data);
      return api.setCredential({
        operationType: existing ? import_cc.UserCredentialOperationType.Modify : import_cc.UserCredentialOperationType.Add,
        userId,
        credentialType: type,
        credentialSlot: slot,
        credentialData
      });
    } else {
      const api = this.#ucAPI();
      const existingStatus = this.getValue(import_UserCodeCC.UserCodeCCValues.userIdStatus(userId).endpoint(this.endpoint.index));
      const status = existingStatus == void 0 || existingStatus === import_cc.UserIDStatus.Available ? import_cc.UserIDStatus.Enabled : existingStatus;
      const existingCred = this.#getCredentialCached_UC(userId, type, slot);
      const codeData = typeof data === "string" ? data : import_shared.Bytes.from(data);
      const result = await api.set(userId, status, codeData);
      let succeeded;
      if (result == void 0) {
        const verified = await api.get(userId);
        succeeded = verified?.userCode === codeData;
      } else {
        succeeded = (0, import_core.supervisedCommandSucceeded)(result);
      }
      if (succeeded) {
        const node = this.endpoint.tryGetNode();
        if (node) {
          node.emit(existingCred ? "credential modified" : "credential added", this.endpoint, {
            userId,
            credentialType: type,
            credentialSlot: slot,
            data
          });
        }
      }
      return result;
    }
  }
  /**
   * Deletes the given credential.
   * This communicates with the node.
   */
  async deleteCredential(userId, type, slot) {
    this.#assertValidSlot(type, slot);
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      return api.setCredential({
        operationType: import_cc.UserCredentialOperationType.Delete,
        userId,
        credentialType: type,
        credentialSlot: slot
      });
    } else {
      const existed = this.#getCredentialCached_UC(userId, type, slot) != void 0;
      const api = this.#ucAPI();
      const result = await api.clear(userId);
      let succeeded;
      if (result == void 0) {
        const verified = await api.get(userId);
        succeeded = existed && verified?.userIdStatus === import_cc.UserIDStatus.Available;
      } else {
        succeeded = (0, import_core.supervisedCommandSucceeded)(result) && existed;
      }
      if (succeeded) {
        const node = this.endpoint.tryGetNode();
        if (node) {
          node.emit("credential deleted", this.endpoint, {
            userId,
            credentialType: type,
            credentialSlot: slot
          });
          node.emit("user deleted", this.endpoint, { userId });
        }
      }
      return result;
    }
  }
  /**
   * Starts a learn process for the given credential slot, allowing a user
   * to input a credential directly on the device.
   * Only supported on nodes using the User Credential CC.
   * This communicates with the node.
   */
  async startCredentialLearn(userId, type, slot, timeout) {
    if (!this.#usesUserCredentialCC) {
      throw new import_core.ZWaveError("This node does not support learning credentials", import_core.ZWaveErrorCodes.CC_NotSupported);
    }
    this.#assertValidSlot(type, slot);
    const existing = this.#getCredentialCached_U3C(userId, type, slot);
    const operationType = existing ? import_cc.UserCredentialOperationType.Modify : import_cc.UserCredentialOperationType.Add;
    timeout ??= this.getCredentialCapabilitiesCached().supportedCredentialTypes.get(type)?.credentialLearnRecommendedTimeout;
    if (timeout == void 0) {
      throw new import_core.ZWaveError(`Credential learning is not supported for credential type ${(0, import_shared.getEnumMemberName)(import_cc.UserCredentialType, type)}`, import_core.ZWaveErrorCodes.CC_NotSupported);
    }
    const api = this.#u3cAPI();
    return api.startCredentialLearn({
      userId,
      credentialType: type,
      credentialSlot: slot,
      operationType,
      learnTimeout: timeout
    });
  }
  /**
   * Cancels an ongoing credential learn process.
   * Only supported on nodes using the User Credential CC.
   * This communicates with the node.
   */
  async cancelCredentialLearn() {
    if (!this.#usesUserCredentialCC) {
      throw new import_core.ZWaveError("This node does not support learning credentials", import_core.ZWaveErrorCodes.CC_NotSupported);
    }
    const api = this.#u3cAPI();
    return api.cancelCredentialLearn();
  }
  /**
   * Retrieves the admin code from the node.
   * This communicates with the node to retrieve fresh information.
   */
  async getAdminCode() {
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      return api.getAdminPinCode();
    } else {
      const api = this.#ucAPI();
      return api.getAdminCode();
    }
  }
  /**
   * Sets the admin code on the node.
   * This communicates with the node.
   */
  async setAdminCode(code) {
    if (this.#usesUserCredentialCC) {
      const api = this.#u3cAPI();
      return api.setAdminPinCode({ pinCode: code });
    } else {
      const api = this.#ucAPI();
      return api.setAdminCode(code);
    }
  }
  #ucAPI() {
    return this.endpoint.commandClasses["User Code"];
  }
  #u3cAPI() {
    return this.endpoint.commandClasses["User Credential"];
  }
  /** Returns the credential type to use for User Code CC based on supported characters */
  get #ucCredentialType() {
    const supportedASCIIChars = this.getValue(import_UserCodeCC.UserCodeCCValues.supportedASCIIChars.endpoint(this.endpoint.index));
    return supportsNonPINChars(supportedASCIIChars) ? import_cc.UserCredentialType.Password : import_cc.UserCredentialType.PINCode;
  }
  /** Maps User Code CC's UserIDStatus to the unified active/userType model */
  #mapUserCodeStatusToUserData(userId, status) {
    if (status === import_cc.UserIDStatus.Available || status === import_cc.UserIDStatus.StatusNotAvailable || status === import_cc.UserIDStatus.PassageMode) {
      return void 0;
    }
    let active;
    let userType;
    switch (status) {
      case import_cc.UserIDStatus.Enabled:
        active = true;
        userType = import_cc.UserCredentialUserType.General;
        break;
      case import_cc.UserIDStatus.Disabled:
        active = false;
        userType = import_cc.UserCredentialUserType.General;
        break;
      // Messaging is the closest User Code CC equivalent to NonAccess
      case import_cc.UserIDStatus.Messaging:
        active = true;
        userType = import_cc.UserCredentialUserType.NonAccess;
        break;
      default:
        active = true;
        userType = import_cc.UserCredentialUserType.General;
        break;
    }
    return { userId, active, userType };
  }
  /** Removes cached credential values for a given user from the value DB */
  #purgeCachedCredentials(userId) {
    const valueDB = this.endpoint.tryGetNode()?.valueDB;
    if (!valueDB)
      return;
    const credentialValues = valueDB.findValues((vid) => (import_UserCredentialCC.UserCredentialCCValues.credential.is(vid) || import_UserCredentialCC.UserCredentialCCValues.credentialModifierType.is(vid) || import_UserCredentialCC.UserCredentialCCValues.credentialModifierNodeId.is(vid)) && vid.propertyKey >> 24 === userId);
    for (const vid of credentialValues) {
      valueDB.removeValue(vid);
    }
  }
  /** Removes all cached user and credential values from the value DB */
  #purgeAllCachedUsersAndCredentials() {
    const valueDB = this.endpoint.tryGetNode()?.valueDB;
    if (!valueDB)
      return;
    const maxUsers = this.getValue(import_UserCredentialCC.UserCredentialCCValues.supportedUsers.endpoint(this.endpoint.index)) ?? 0;
    for (let userId = 1; userId <= maxUsers; userId++) {
      for (const value of [
        import_UserCredentialCC.UserCredentialCCValues.userType(userId),
        import_UserCredentialCC.UserCredentialCCValues.userActive(userId),
        import_UserCredentialCC.UserCredentialCCValues.credentialRule(userId),
        import_UserCredentialCC.UserCredentialCCValues.expiringTimeoutMinutes(userId),
        import_UserCredentialCC.UserCredentialCCValues.userName(userId),
        import_UserCredentialCC.UserCredentialCCValues.userModifierType(userId),
        import_UserCredentialCC.UserCredentialCCValues.userModifierNodeId(userId),
        import_UserCredentialCC.UserCredentialCCValues.userChecksum(userId)
      ]) {
        valueDB.removeValue(value.endpoint(this.endpoint.index));
      }
    }
    const credentialValues = valueDB.findValues((vid) => import_UserCredentialCC.UserCredentialCCValues.credential.is(vid) || import_UserCredentialCC.UserCredentialCCValues.credentialModifierType.is(vid) || import_UserCredentialCC.UserCredentialCCValues.credentialModifierNodeId.is(vid));
    for (const vid of credentialValues) {
      valueDB.removeValue(vid);
    }
  }
  /** Removes all cached user code status and code values from the value DB */
  #purgeAllCachedUserCodes() {
    const valueDB = this.endpoint.tryGetNode()?.valueDB;
    if (!valueDB)
      return;
    const values = valueDB.findValues((vid) => import_UserCodeCC.UserCodeCCValues.userIdStatus.is(vid) || import_UserCodeCC.UserCodeCCValues.userCode.is(vid));
    for (const vid of values) {
      valueDB.removeValue(vid);
    }
  }
  #assertValidSlot(type, slot) {
    const caps = this.getCredentialCapabilitiesCached().supportedCredentialTypes.get(type);
    if (!caps || slot < 1 || slot > caps.numberOfCredentialSlots) {
      throw new import_core.ZWaveError(`Credential slot ${slot} is out of range for credential type ${(0, import_shared.getEnumMemberName)(import_cc.UserCredentialType, type)}`, import_core.ZWaveErrorCodes.Argument_Invalid);
    }
  }
  #getUserCached_U3C(userId) {
    const userType = this.getValue(import_UserCredentialCC.UserCredentialCCValues.userType(userId).endpoint(this.endpoint.index));
    if (userType == void 0)
      return void 0;
    return {
      userId,
      active: this.getValue(import_UserCredentialCC.UserCredentialCCValues.userActive(userId).endpoint(this.endpoint.index)) ?? false,
      userType,
      userName: this.getValue(import_UserCredentialCC.UserCredentialCCValues.userName(userId).endpoint(this.endpoint.index)) ?? void 0,
      credentialRule: this.getValue(import_UserCredentialCC.UserCredentialCCValues.credentialRule(userId).endpoint(this.endpoint.index)) ?? void 0,
      expiringTimeoutMinutes: this.getValue(import_UserCredentialCC.UserCredentialCCValues.expiringTimeoutMinutes(userId).endpoint(this.endpoint.index)) || void 0
    };
  }
  #getCredentialCached_U3C(userId, type, slot) {
    const data = this.getValue(import_UserCredentialCC.UserCredentialCCValues.credential(userId, type, slot).endpoint(this.endpoint.index));
    if (data == void 0)
      return void 0;
    return { userId, type, slot, data };
  }
  #getUserCached_UC(userId) {
    const status = this.getValue(import_UserCodeCC.UserCodeCCValues.userIdStatus(userId).endpoint(this.endpoint.index));
    if (status == void 0)
      return void 0;
    return this.#mapUserCodeStatusToUserData(userId, status);
  }
  #getCredentialCached_UC(userId, type, slot) {
    if (slot !== 1)
      return void 0;
    const status = this.getValue(import_UserCodeCC.UserCodeCCValues.userIdStatus(userId).endpoint(this.endpoint.index));
    if (status == void 0 || status === import_cc.UserIDStatus.Available || status === import_cc.UserIDStatus.StatusNotAvailable) {
      return void 0;
    }
    const data = this.getValue(import_UserCodeCC.UserCodeCCValues.userCode(userId).endpoint(this.endpoint.index));
    if (data == void 0)
      return void 0;
    return { userId, type, slot, data };
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  AccessControlAPI
});
//# sourceMappingURL=AccessControl.js.map
