"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 BtpCodec_exports = {};
__export(BtpCodec_exports, {
  BtpCodec: () => BtpCodec,
  BtpHeaderBits: () => BtpHeaderBits,
  BtpOpcode: () => BtpOpcode
});
module.exports = __toCommonJS(BtpCodec_exports);
var import_general = require("@matter/general");
var import_Ble = require("../ble/Ble.js");
var import_BtpSessionHandler = require("../ble/BtpSessionHandler.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
var BtpHeaderBits = /* @__PURE__ */ ((BtpHeaderBits2) => {
  BtpHeaderBits2[BtpHeaderBits2["HandshakeBit"] = 64] = "HandshakeBit";
  BtpHeaderBits2[BtpHeaderBits2["ManagementMsg"] = 32] = "ManagementMsg";
  BtpHeaderBits2[BtpHeaderBits2["AckMsg"] = 8] = "AckMsg";
  BtpHeaderBits2[BtpHeaderBits2["EndSegment"] = 4] = "EndSegment";
  BtpHeaderBits2[BtpHeaderBits2["ContinuingSegment"] = 2] = "ContinuingSegment";
  BtpHeaderBits2[BtpHeaderBits2["BeginSegment"] = 1] = "BeginSegment";
  return BtpHeaderBits2;
})(BtpHeaderBits || {});
var BtpOpcode = /* @__PURE__ */ ((BtpOpcode2) => {
  BtpOpcode2[BtpOpcode2["HandshakeManagementOpcode"] = 108] = "HandshakeManagementOpcode";
  return BtpOpcode2;
})(BtpOpcode || {});
const HANDSHAKE_HEADER = 101;
class BtpCodec {
  static decodeBtpHandshakeRequest(data) {
    const reader = new import_general.DataReader(data, import_general.Endian.Little);
    return this.decodeHandshakeRequestPayload(reader);
  }
  static decodeBtpPacket(data) {
    const reader = new import_general.DataReader(data, import_general.Endian.Little);
    const header = this.decodeBtpPacketHeader(reader);
    return {
      header,
      payload: this.decodeBtpPacketPayload(reader, header)
    };
  }
  static encodeBtpPacket({ header, payload }) {
    return import_general.Bytes.concat(this.encodeBtpPacketHeader(header), this.encodeBtpPacketPayload(header, payload));
  }
  static encodeBtpHandshakeRequest({ versions, attMtu, clientWindowSize }) {
    const writer = new import_general.DataWriter(import_general.Endian.Little);
    writer.writeUInt8(HANDSHAKE_HEADER);
    writer.writeUInt8(108 /* HandshakeManagementOpcode */);
    writer.writeUInt8(versions[1] << 4 | versions[0]);
    writer.writeUInt8(versions[3] << 4 | versions[2]);
    writer.writeUInt8(versions[5] << 4 | versions[4]);
    writer.writeUInt8(versions[7] << 4 | versions[6]);
    writer.writeUInt16(attMtu);
    writer.writeUInt8(clientWindowSize);
    return writer.toByteArray();
  }
  static encodeBtpHandshakeResponse({ version, attMtu, windowSize }) {
    const writer = new import_general.DataWriter(import_general.Endian.Little);
    writer.writeUInt8(HANDSHAKE_HEADER);
    writer.writeUInt8(108 /* HandshakeManagementOpcode */);
    writer.writeUInt8(version & 15);
    writer.writeUInt16(attMtu);
    writer.writeUInt8(windowSize);
    return writer.toByteArray();
  }
  static decodeBtpPacketPayload(reader, header) {
    const { hasAckNumber, isBeginningSegment } = header;
    const ackNumber = hasAckNumber ? reader.readUInt8() : void 0;
    const sequenceNumber = reader.readUInt8();
    const messageLength = isBeginningSegment ? reader.readUInt16() : void 0;
    const segmentPayload = reader.remainingBytes;
    return { ackNumber, sequenceNumber, messageLength, segmentPayload };
  }
  static encodeBtpPacketPayload({ hasAckNumber, isBeginningSegment, isContinuingSegment, isEndingSegment }, { ackNumber, sequenceNumber, messageLength, segmentPayload }) {
    const writer = new import_general.DataWriter(import_general.Endian.Little);
    if (!hasAckNumber && ackNumber !== void 0) {
      throw new import_BtpSessionHandler.BtpProtocolError("Ack number shouldn't be set because header flag is not set.");
    }
    if (hasAckNumber && ackNumber === void 0) {
      throw new import_BtpSessionHandler.BtpProtocolError("Ack number needs to be set because header flag is set.");
    }
    if (isBeginningSegment && isContinuingSegment) {
      throw new import_BtpSessionHandler.BtpProtocolError("Beginning and continuing segment flags can't be set at the same time.");
    }
    if (isEndingSegment && !isContinuingSegment && !isBeginningSegment) {
      throw new import_BtpSessionHandler.BtpProtocolError("Ending segment flag can't be set without continuing segment flag.");
    }
    if ((isBeginningSegment || isContinuingSegment) && (segmentPayload === void 0 || segmentPayload.byteLength === 0)) {
      throw new import_BtpSessionHandler.BtpProtocolError("Payload needs to be set because header flag indicates a message with payload.");
    }
    if (isBeginningSegment && messageLength === void 0) {
      throw new import_BtpSessionHandler.BtpProtocolError("Message length needs to be set because packet is a beginning segment.");
    }
    if (!isBeginningSegment && messageLength !== void 0) {
      throw new import_BtpSessionHandler.BtpProtocolError(
        "Message length shouldn't be set because the package is not a beginning segment."
      );
    }
    if (ackNumber !== void 0) {
      writer.writeUInt8(ackNumber);
    }
    writer.writeUInt8(sequenceNumber);
    if (messageLength !== void 0) {
      writer.writeUInt16(messageLength);
    }
    if (segmentPayload !== void 0) {
      writer.writeByteArray(segmentPayload);
    }
    return writer.toByteArray();
  }
  static decodeHandshakeRequestPayload(reader) {
    const header = reader.readUInt8();
    const opcode = reader.readUInt8();
    let version = reader.readUInt8();
    if (header !== HANDSHAKE_HEADER) {
      throw new import_BtpSessionHandler.BtpProtocolError("Header for expected BTP Handshake Request is incorrect.");
    }
    if (opcode !== 108 /* HandshakeManagementOpcode */) {
      throw new import_BtpSessionHandler.BtpProtocolError("Management Opcode for BTP Handshake Request is incorrect.");
    }
    const ver = [];
    ver[0] = (version & 240) >> 4;
    ver[1] = version & 15;
    version = reader.readUInt8();
    ver[2] = (version & 240) >> 4;
    ver[3] = version & 15;
    version = reader.readUInt8();
    ver[4] = (version & 240) >> 4;
    ver[5] = version & 15;
    version = reader.readUInt8();
    ver[6] = (version & 240) >> 4;
    ver[7] = version & 15;
    const versions = ver.filter((v) => v !== 0);
    if (versions.length === 0) {
      throw new import_BtpSessionHandler.BtpProtocolError("No valid version provided.");
    }
    const attMtu = reader.readUInt16();
    const clientWindowSize = reader.readUInt8();
    return { versions, attMtu, clientWindowSize };
  }
  static decodeBtpHandshakeResponsePayload(data) {
    const reader = new import_general.DataReader(data, import_general.Endian.Little);
    const header = reader.readUInt8();
    if (header !== HANDSHAKE_HEADER) {
      throw new import_BtpSessionHandler.BtpProtocolError("Header for expected BTP Handshake Request is incorrect.");
    }
    const opcode = reader.readUInt8();
    if (opcode !== 108 /* HandshakeManagementOpcode */) {
      throw new import_BtpSessionHandler.BtpProtocolError("Management Opcode for BTP Handshake Request is incorrect.");
    }
    const version = reader.readUInt8() & 15;
    const attMtu = reader.readUInt16();
    const windowSize = reader.readUInt8();
    return { version, attMtu, windowSize };
  }
  static decodeBtpPacketHeader(reader) {
    const headerBits = reader.readUInt8();
    const isHandshakeRequest = (headerBits & 64 /* HandshakeBit */) !== 0;
    const hasManagementOpcode = (headerBits & 32 /* ManagementMsg */) !== 0;
    const hasAckNumber = (headerBits & 8 /* AckMsg */) !== 0;
    const isEndingSegment = (headerBits & 4 /* EndSegment */) !== 0;
    const isContinuingSegment = (headerBits & 2 /* ContinuingSegment */) !== 0;
    const isBeginningSegment = (headerBits & 1 /* BeginSegment */) !== 0;
    if (hasManagementOpcode) {
      throw new import_BtpSessionHandler.BtpProtocolError("Management Opcode for BTPHandshake Request is not expected");
    }
    return {
      isHandshakeRequest,
      hasManagementOpcode,
      hasAckNumber,
      isEndingSegment,
      isContinuingSegment,
      isBeginningSegment
    };
  }
  static encodeBtpPacketHeader({
    isHandshakeRequest,
    hasManagementOpcode,
    hasAckNumber,
    isEndingSegment,
    isContinuingSegment,
    isBeginningSegment
  }) {
    const writer = new import_general.DataWriter(import_general.Endian.Little);
    if (isHandshakeRequest || hasManagementOpcode) {
      throw new import_BtpSessionHandler.BtpProtocolError("Please use the specific methods to encode a Handshake packet");
    }
    const header = (
      // (isHandshakeRequest ? BtpHeaderBits.HandshakeBit : 0) | ... but always false here
      // (hasManagementOpcode ? BtpHeaderBits.ManagementMsg : 0) | ... but alw<ys false here
      (hasAckNumber ? 8 /* AckMsg */ : 0) | (isEndingSegment ? 4 /* EndSegment */ : 0) | (isContinuingSegment ? 2 /* ContinuingSegment */ : 0) | (isBeginningSegment ? 1 /* BeginSegment */ : 0)
    );
    writer.writeUInt8(header);
    return writer.toByteArray();
  }
  static encodeBleAdvertisementData(discriminator, vendorId, productId, hasAdditionalAdvertisementData = false, isExtendedAnnouncement = false) {
    const writer = new import_general.DataWriter(import_general.Endian.Little);
    writer.writeUInt8(2);
    writer.writeUInt8(1);
    writer.writeUInt8(6);
    writer.writeUInt8(11);
    writer.writeUInt8(22);
    writer.writeUInt16(65526);
    writer.writeUInt8(0);
    writer.writeUInt16(discriminator);
    writer.writeUInt16(isExtendedAnnouncement ? 0 : vendorId);
    writer.writeUInt16(isExtendedAnnouncement ? 0 : productId);
    writer.writeUInt8((hasAdditionalAdvertisementData ? 1 : 0) | (isExtendedAnnouncement ? 2 : 0));
    return writer.toByteArray();
  }
  static decodeBleAdvertisementData(data) {
    const reader = new import_general.DataReader(data, import_general.Endian.Little);
    if (reader.readUInt8() !== 2 || reader.readUInt8() !== 1 || reader.readUInt8() !== 6 || reader.readUInt8() !== 11 || reader.readUInt8() !== 22) {
      throw new import_Ble.BleError("Invalid BLE advertisement data");
    }
    const serviceUuid = reader.readUInt16();
    if (serviceUuid !== 65526) {
      throw new import_Ble.BleError("Invalid BLE advertisement data");
    }
    const { discriminator, vendorId, productId, hasAdditionalAdvertisementData } = this.decodeBleAdvertisementServiceData(reader.remainingBytes);
    return { discriminator, vendorId, productId, hasAdditionalAdvertisementData };
  }
  static decodeBleAdvertisementServiceData(data) {
    const reader = new import_general.DataReader(data, import_general.Endian.Little);
    if (reader.readUInt8() !== 0) {
      throw new import_Ble.BleError("Invalid BLE advertisement data");
    }
    const discriminator = reader.readUInt16();
    const vendorId = reader.readUInt16();
    const productId = reader.readUInt16();
    const hasAdditionalAdvertisementData = !!reader.readUInt8();
    return { discriminator, vendorId, productId, hasAdditionalAdvertisementData };
  }
}
//# sourceMappingURL=BtpCodec.js.map
