"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 NotificationCC_exports = {};
__export(NotificationCC_exports, {
  getDefaultNotificationHandlerStore: () => getDefaultNotificationHandlerStore,
  handleNotificationReport: () => handleNotificationReport,
  manuallyIdleNotificationValueInternal: () => manuallyIdleNotificationValueInternal
});
module.exports = __toCommonJS(NotificationCC_exports);
var import_cc = require("@zwave-js/cc");
var import_NotificationCC = require("@zwave-js/cc/NotificationCC");
var import_core = require("@zwave-js/core");
var import_shared = require("@zwave-js/shared");
function getDefaultNotificationHandlerStore() {
  return {
    idleTimeouts: /* @__PURE__ */ new Map()
  };
}
__name(getDefaultNotificationHandlerStore, "getDefaultNotificationHandlerStore");
function handleNotificationReport(ctx, node, command, store) {
  if (command.notificationType == void 0) {
    if (command.alarmType == void 0) {
      ctx.logNode(node.id, {
        message: `received unsupported notification ${(0, import_shared.stringify)(command)}`,
        direction: "inbound"
      });
    }
    return;
  }
  const remappings = node.deviceConfig?.compat?.remapNotifications;
  if (remappings?.length) {
    const match = remappings.find((m) => m.from.notificationType === command.notificationType && m.from.notificationEvent === command.notificationEvent);
    if (match) {
      ctx.logNode(node.id, {
        message: `Notification remapped via compat flag`,
        direction: "inbound",
        level: "verbose"
      });
      if (match.action.type === "clear" || match.action.type === "idle") {
        for (const target of match.action.targets) {
          const targetNotification = (0, import_core.getNotification)(target.notificationType);
          if (!targetNotification)
            continue;
          const targetValueConfig = (0, import_core.getNotificationValue)(targetNotification, target.notificationEvent);
          if (targetValueConfig?.type !== "state")
            continue;
          const valueId = import_cc.NotificationCCValues.notificationVariable(targetNotification.name, targetValueConfig.variableName).endpoint(command.endpointIndex);
          if (match.action.type === "clear") {
            if (node.valueDB.getValue(valueId) === target.notificationEvent) {
              node.valueDB.setValue(valueId, import_core.UNKNOWN_STATE);
            }
            if (target.notificationType === 6 && (target.notificationEvent === 22 || target.notificationEvent === 23)) {
              const simpleDoorStateId = import_cc.NotificationCCValues.deprecated_doorStateSimple.endpoint(command.endpointIndex);
              if (node.valueDB.getValue(simpleDoorStateId) === target.notificationEvent) {
                node.valueDB.setValue(simpleDoorStateId, import_core.UNKNOWN_STATE);
              }
            }
          } else {
            node.valueDB.setValue(
              valueId,
              0
              /* idle */
            );
          }
        }
        return;
      } else {
        const to = match.action.to;
        command.notificationType = to.notificationType;
        command.notificationEvent = to.notificationEvent;
      }
    }
  }
  const ccVersion = (0, import_cc.getEffectiveCCVersion)(ctx, command);
  const notification = (0, import_core.getNotification)(command.notificationType);
  if (notification) {
    const notificationName = notification.name;
    ctx.logNode(node.id, {
      message: `[handleNotificationReport] notificationName: ${notificationName}`,
      level: "silly"
    });
    const setStateIdle = /* @__PURE__ */ __name((prevValue) => {
      manuallyIdleNotificationValueInternal(ctx, node, store, notification, prevValue, command.endpointIndex);
    }, "setStateIdle");
    const setUnknownStateIdle = /* @__PURE__ */ __name((prevValue) => {
      const unknownNotificationVariableValueId = import_cc.NotificationCCValues.unknownNotificationVariable(command.notificationType, notificationName).endpoint(command.endpointIndex);
      const currentValue = node.valueDB.getValue(unknownNotificationVariableValueId);
      if (currentValue == void 0)
        return;
      if (prevValue == void 0 || currentValue === prevValue) {
        node.valueDB.setValue(unknownNotificationVariableValueId, 0);
      }
    }, "setUnknownStateIdle");
    const value = command.notificationEvent;
    if (value === 0) {
      if ((0, import_shared.isUint8Array)(command.eventParameters) && command.eventParameters.length) {
        setStateIdle(command.eventParameters[0]);
        setUnknownStateIdle(command.eventParameters[0]);
      } else {
        const nonIdleValues = node.valueDB.getValues(import_core.CommandClasses.Notification).filter((v) => (v.endpoint || 0) === command.endpointIndex && v.property === notificationName && typeof v.value === "number" && v.value !== 0);
        for (const v of nonIdleValues) {
          setStateIdle(v.value);
        }
        setUnknownStateIdle();
      }
      return;
    }
    const valueConfig = (0, import_core.getNotificationValue)(notification, value);
    if (valueConfig) {
      ctx.logNode(node.id, {
        message: `[handleNotificationReport] valueConfig:
  label: ${valueConfig.label}
  ${valueConfig.type === "event" ? "type: event" : `type: state
  variableName: ${valueConfig.variableName}`}`,
        level: "silly"
      });
    } else {
      ctx.logNode(node.id, {
        message: `[handleNotificationReport] valueConfig: undefined`,
        level: "silly"
      });
    }
    handleKnownNotification(ctx, node, command);
    let allowIdleReset;
    if (!valueConfig) {
      allowIdleReset = false;
    } else if (valueConfig.type === "state") {
      allowIdleReset = valueConfig.idle;
    } else {
      const endpoint = node.getEndpoint(command.endpointIndex) ?? node;
      const eventArgs = {
        type: command.notificationType,
        event: value,
        label: notification.name,
        eventLabel: valueConfig.label,
        parameters: command.eventParameters
      };
      const prefs = ctx.getUserPreferences();
      if (prefs.lookupUserIdInNotificationEvents && command.eventParameters != null && typeof command.eventParameters === "object" && !(0, import_shared.isUint8Array)(command.eventParameters) && "userId" in command.eventParameters && typeof command.eventParameters.userId === "number") {
        const userId = command.eventParameters.userId;
        const nodeEndpoint = {
          nodeId: node.id,
          index: command.endpointIndex,
          virtual: false
        };
        const enhancedParameters = {
          ...command.eventParameters
        };
        const userIdStatus = import_cc.UserCodeCC.getUserIdStatusCached(ctx, nodeEndpoint, userId);
        if (userIdStatus != null) {
          enhancedParameters.userIdStatus = userIdStatus;
        }
        const userCode = import_cc.UserCodeCC.getUserCodeCached(ctx, nodeEndpoint, userId);
        if (userCode != null) {
          enhancedParameters.userCode = userCode;
        }
        eventArgs.parameters = enhancedParameters;
      }
      node.emit("notification", endpoint, import_core.CommandClasses.Notification, eventArgs);
      if (valueConfig.idleVariables?.length) {
        for (const variable of valueConfig.idleVariables) {
          setStateIdle(variable);
        }
      }
      return;
    }
    let valueId;
    if (valueConfig) {
      valueId = import_cc.NotificationCCValues.notificationVariable(notificationName, valueConfig.variableName).endpoint(command.endpointIndex);
      extendNotificationValueMetadata(ctx, node, valueId, notification, valueConfig);
    } else {
      const unknownValue = import_cc.NotificationCCValues.unknownNotificationVariable(command.notificationType, notificationName);
      valueId = unknownValue.endpoint(command.endpointIndex);
      if (ccVersion >= 2) {
        if (!node.valueDB.hasMetadata(valueId)) {
          node.valueDB.setMetadata(valueId, unknownValue.meta);
        }
      }
    }
    if (typeof command.eventParameters === "number") {
      const enumBehavior = valueConfig ? (0, import_NotificationCC.getNotificationEnumBehavior)(notification, valueConfig) : "extend";
      const valueWithEnum = enumBehavior === "replace" ? command.eventParameters : (0, import_NotificationCC.getNotificationStateValueWithEnum)(value, command.eventParameters);
      node.valueDB.setValue(valueId, valueWithEnum);
    } else {
      node.valueDB.setValue(valueId, value);
    }
    if (allowIdleReset && !!node.deviceConfig?.compat?.forceNotificationIdleReset) {
      ctx.logNode(node.id, {
        message: `[handleNotificationReport] scheduling idle reset`,
        level: "silly"
      });
      scheduleNotificationIdleReset(store, valueId, () => setStateIdle(value));
    }
  } else {
    const unknownValue = import_cc.NotificationCCValues.unknownNotificationType(command.notificationType);
    const valueId = unknownValue.endpoint(command.endpointIndex);
    if (ccVersion >= 2) {
      if (!node.valueDB.hasMetadata(valueId)) {
        node.valueDB.setMetadata(valueId, unknownValue.meta);
      }
    }
    node.valueDB.setValue(valueId, command.notificationEvent);
  }
}
__name(handleNotificationReport, "handleNotificationReport");
function handleKnownNotification(ctx, node, command) {
  const lockEvents = /* @__PURE__ */ new Set([1, 3, 5, 9]);
  const unlockEvents = /* @__PURE__ */ new Set([2, 4, 6]);
  const doorStatusEvents = [
    // Actual status
    22,
    23,
    // Synthetic status with enum (deprecated)
    5632,
    5633
  ];
  if (
    // Access Control, manual/keypad/rf/auto (un)lock operation
    command.notificationType === 6 && (lockEvents.has(command.notificationEvent) || unlockEvents.has(command.notificationEvent)) && (node.supportsCC(import_core.CommandClasses["Door Lock"]) || node.supportsCC(import_core.CommandClasses.Lock))
  ) {
    const isLocked = lockEvents.has(command.notificationEvent);
    if (node.supportsCC(import_core.CommandClasses["Door Lock"])) {
      node.valueDB.setValue(import_cc.DoorLockCCValues.currentMode.endpoint(command.endpointIndex), isLocked ? import_cc.DoorLockMode.Secured : import_cc.DoorLockMode.Unsecured);
    }
    if (node.supportsCC(import_core.CommandClasses.Lock)) {
      node.valueDB.setValue(import_cc.LockCCValues.locked.endpoint(command.endpointIndex), isLocked);
    }
  } else if (command.notificationType === 6 && doorStatusEvents.includes(command.notificationEvent)) {
    const isTilted = command.notificationEvent === 22 && command.eventParameters === 1;
    const openingStateValue = import_cc.NotificationCCValues.openingState;
    const openingStateValueId = openingStateValue.endpoint(command.endpointIndex);
    const openingStateTiltMetadata = {
      ...openingStateValue.meta,
      states: {
        ...openingStateValue.meta.states,
        [2]: "Tilted"
      }
    };
    const openingStateMetadata = node.valueDB.getMetadata(openingStateValueId);
    if (isTilted && !openingStateMetadata?.states?.[2]) {
      node.valueDB.setMetadata(openingStateValueId, openingStateTiltMetadata);
    }
    node.valueDB.setValue(openingStateValueId, command.notificationEvent === 23 ? 0 : isTilted ? 2 : 1);
    node.valueDB.setValue(import_cc.NotificationCCValues.deprecated_doorStateSimple.endpoint(command.endpointIndex), command.notificationEvent === 23 ? 23 : 22);
    const tiltValue = import_cc.NotificationCCValues.deprecated_doorTiltState;
    const tiltValueId = tiltValue.endpoint(command.endpointIndex);
    let tiltValueWasCreated = node.valueDB.hasMetadata(tiltValueId);
    if (isTilted && !tiltValueWasCreated) {
      node.valueDB.setMetadata(tiltValueId, tiltValue.meta);
      tiltValueWasCreated = true;
    }
    if (tiltValueWasCreated) {
      node.valueDB.setValue(tiltValueId, isTilted ? 1 : 0);
    }
  } else if (
    // Access Control, all user codes deleted
    command.notificationType === 6 && command.notificationEvent === 12 && node.supportsCC(import_core.CommandClasses["User Code"])
  ) {
    const endpoint = {
      nodeId: node.id,
      index: command.endpointIndex,
      virtual: false
    };
    const numUsers = import_cc.UserCodeCC.getSupportedUsersCached(ctx, endpoint) ?? 0;
    for (let userId = 1; userId <= numUsers; userId++) {
      import_cc.UserCodeCC.setUserIdStatusCached(ctx, endpoint, userId, import_cc.UserIDStatus.Available);
      import_cc.UserCodeCC.setUserCodeCached(ctx, endpoint, userId, "");
    }
  }
}
__name(handleKnownNotification, "handleKnownNotification");
function manuallyIdleNotificationValueInternal(ctx, node, store, notification, prevValue, endpointIndex) {
  const valueConfig = (0, import_core.getNotificationValue)(notification, prevValue);
  if (!valueConfig || valueConfig.type !== "state")
    return;
  if (!valueConfig.idle)
    return;
  const notificationName = notification.name;
  const variableName = valueConfig.variableName;
  const valueId = import_cc.NotificationCCValues.notificationVariable(notificationName, variableName).endpoint(endpointIndex);
  if (node.valueDB.getValue(valueId) !== prevValue)
    return;
  clearNotificationIdleReset(store, valueId);
  extendNotificationValueMetadata(ctx, node, valueId, notification, valueConfig);
  node.valueDB.setValue(
    valueId,
    0
    /* idle */
  );
}
__name(manuallyIdleNotificationValueInternal, "manuallyIdleNotificationValueInternal");
function scheduleNotificationIdleReset(store, valueId, handler) {
  clearNotificationIdleReset(store, valueId);
  const key = (0, import_core.valueIdToString)(valueId);
  store.idleTimeouts.set(
    key,
    // Unref'ing long running timeouts allows to quit the application before the timeout elapses
    (0, import_shared.setTimer)(
      handler,
      5 * 60 * 1e3
      /* 5 minutes */
    ).unref()
  );
}
__name(scheduleNotificationIdleReset, "scheduleNotificationIdleReset");
function clearNotificationIdleReset(store, valueId) {
  const key = (0, import_core.valueIdToString)(valueId);
  if (store.idleTimeouts.has(key)) {
    store.idleTimeouts.get(key)?.clear();
    store.idleTimeouts.delete(key);
  }
}
__name(clearNotificationIdleReset, "clearNotificationIdleReset");
function extendNotificationValueMetadata(ctx, node, valueId, notification, valueConfig) {
  const ccVersion = ctx.getSupportedCCVersion(import_core.CommandClasses.Notification, node.id, node.index);
  if (ccVersion === 2 || !node.valueDB.hasMetadata(valueId)) {
    const metadata = (0, import_NotificationCC.getNotificationValueMetadata)(node.valueDB.getMetadata(valueId), notification, valueConfig);
    node.valueDB.setMetadata(valueId, metadata);
  }
}
__name(extendNotificationValueMetadata, "extendNotificationValueMetadata");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  getDefaultNotificationHandlerStore,
  handleNotificationReport,
  manuallyIdleNotificationValueInternal
});
//# sourceMappingURL=NotificationCC.js.map
