/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { InternalError, MatterError } from "#general";
import { MAX_COUNTER_VALUE_32BIT } from "./MessageCounter.js";
const MAX_COUNTER_INCREASE_2POW31 = Math.pow(2, 31);
const MSG_COUNTER_WINDOW_SIZE = 32;
class DuplicateMessageError extends MatterError {
}
class MessageReceptionState {
}
class MessageReceptionStateEncryptedWithoutRollover extends MessageReceptionState {
  maximumMessageCounter;
  messageCounterBitmap = 4294967295;
  // All bits set to 1
  constructor(messageCounter) {
    super();
    if (messageCounter !== void 0) {
      this.initialize(messageCounter);
    }
  }
  /** Initialize the message counter state. */
  initialize(messageCounter) {
    this.maximumMessageCounter = messageCounter;
    this.messageCounterBitmap = 4294967295;
  }
  /**
   * Calculate plain diff without rollover.
   * This method is mainly overridden for other counter types and follow the following semantic
   * Return number is:
   * * negative if the new message counter is smaller than the current maximum. Smaller values within the Window size
   *   are check separately within the window. Other smaller values are considered DUPLICATE
   * * positive if the new message counter is larger than the current maximum and are always NEW
   */
  calculateDiff(messageCounter) {
    if (this.maximumMessageCounter === void 0) {
      return 0;
    }
    return messageCounter - this.maximumMessageCounter;
  }
  /** Update or move the message counter window. */
  calculateMessageCounterBitmap(messageCounterBitmap, diff) {
    if (diff < 0) {
      if (diff < -MSG_COUNTER_WINDOW_SIZE) {
        throw new InternalError(`Message counter difference too large: ${diff}`);
      }
      const bit = 1 << -diff - 1;
      messageCounterBitmap |= bit;
    } else if (diff > 0) {
      if (diff <= MSG_COUNTER_WINDOW_SIZE) {
        const bit = 1 << diff - 1;
        messageCounterBitmap = messageCounterBitmap << diff >>> 0 | bit;
      } else {
        messageCounterBitmap = 0;
      }
    }
    return messageCounterBitmap >>> 0;
  }
  /** Update the message counter and window. */
  updateMessageCounterAndBitmap(messageCounter, diff) {
    if (this.maximumMessageCounter === void 0) {
      this.initialize(messageCounter);
      return;
    }
    this.messageCounterBitmap = this.calculateMessageCounterBitmap(this.messageCounterBitmap, diff);
    if (diff > 0 || diff < -MSG_COUNTER_WINDOW_SIZE) {
      this.maximumMessageCounter = messageCounter;
    }
  }
  /** Check if the message counter is known in the bitmap. */
  isCounterKnownInBitmap(diff) {
    if (diff < -MSG_COUNTER_WINDOW_SIZE || diff >= 0) {
      throw new InternalError(`Invalid Message counter difference for check: ${diff}`);
    }
    const bit = 1 << -diff - 1;
    return (this.messageCounterBitmap & bit) !== 0;
  }
  /**
   * Returns true if the message counter is a duplicate.
   */
  updateMessageCounter(messageCounter) {
    if (messageCounter < 0 || messageCounter > MAX_COUNTER_VALUE_32BIT) {
      throw new InternalError(`Invalid message counter value: ${messageCounter}`);
    }
    if (this.maximumMessageCounter === void 0) {
      this.updateMessageCounterAndBitmap(messageCounter, 0);
      return;
    }
    if (messageCounter === this.maximumMessageCounter) {
      throw new DuplicateMessageError("Message counter equals the maximum message counter.");
    }
    const diff = this.calculateDiff(messageCounter);
    if (diff < 0) {
      if (diff < -MSG_COUNTER_WINDOW_SIZE) {
        throw new DuplicateMessageError("Message counter is considered duplicate.");
      }
      if (this.isCounterKnownInBitmap(diff)) {
        throw new DuplicateMessageError("Message counter is within the message counter window and duplicate.");
      }
    }
    this.updateMessageCounterAndBitmap(messageCounter, diff);
  }
}
class MessageReceptionStateEncryptedWithRollover extends MessageReceptionStateEncryptedWithoutRollover {
  calculateDiff(messageCounter) {
    if (this.maximumMessageCounter === void 0) {
      return 0;
    }
    const diff = messageCounter - this.maximumMessageCounter;
    if (diff > 0) {
      if (diff < MAX_COUNTER_INCREASE_2POW31) {
        return diff;
      }
      return diff - MAX_COUNTER_VALUE_32BIT - 1;
    } else if (diff < 0) {
      if (diff >= -MAX_COUNTER_INCREASE_2POW31) {
        return diff;
      }
      return diff + MAX_COUNTER_VALUE_32BIT + 1;
    }
    return 0;
  }
}
class MessageReceptionStateUnencryptedWithRollover extends MessageReceptionStateEncryptedWithoutRollover {
  calculateDiff(messageCounter) {
    if (this.maximumMessageCounter === void 0) {
      return 0;
    }
    const diff = messageCounter - this.maximumMessageCounter;
    if (diff > 0) {
      if (-diff + MAX_COUNTER_VALUE_32BIT < MSG_COUNTER_WINDOW_SIZE) {
        return diff - MAX_COUNTER_VALUE_32BIT - 1;
      }
      return diff;
    } else if (diff < 0) {
      if (diff < -MSG_COUNTER_WINDOW_SIZE) {
        return MAX_COUNTER_VALUE_32BIT + diff;
      }
      return diff;
    }
    return 0;
  }
}
export {
  DuplicateMessageError,
  MessageReceptionState,
  MessageReceptionStateEncryptedWithRollover,
  MessageReceptionStateEncryptedWithoutRollover,
  MessageReceptionStateUnencryptedWithRollover
};
//# sourceMappingURL=MessageReceptionState.js.map
