/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import {
  Bytes,
  INT16_MAX,
  INT16_MIN,
  INT32_MAX,
  INT32_MIN,
  INT8_MAX,
  INT8_MIN,
  NotImplementedError,
  UINT16_MAX,
  UINT32_MAX,
  UINT8_MAX,
  UnexpectedDataError
} from "#general";
import { BitField, BitFieldEnum, BitmapSchema } from "../schema/BitmapSchema.js";
var TlvType = /* @__PURE__ */ ((TlvType2) => {
  TlvType2[TlvType2["SignedInt"] = 0] = "SignedInt";
  TlvType2[TlvType2["UnsignedInt"] = 4] = "UnsignedInt";
  TlvType2[TlvType2["Boolean"] = 8] = "Boolean";
  TlvType2[TlvType2["Float"] = 10] = "Float";
  TlvType2[TlvType2["Utf8String"] = 12] = "Utf8String";
  TlvType2[TlvType2["ByteString"] = 16] = "ByteString";
  TlvType2[TlvType2["Null"] = 20] = "Null";
  TlvType2[TlvType2["Structure"] = 21] = "Structure";
  TlvType2[TlvType2["Array"] = 22] = "Array";
  TlvType2[TlvType2["List"] = 23] = "List";
  TlvType2[TlvType2["EndOfContainer"] = 24] = "EndOfContainer";
  return TlvType2;
})(TlvType || {});
var TlvLength = /* @__PURE__ */ ((TlvLength2) => {
  TlvLength2[TlvLength2["OneByte"] = 0] = "OneByte";
  TlvLength2[TlvLength2["TwoBytes"] = 1] = "TwoBytes";
  TlvLength2[TlvLength2["FourBytes"] = 2] = "FourBytes";
  TlvLength2[TlvLength2["EightBytes"] = 3] = "EightBytes";
  return TlvLength2;
})(TlvLength || {});
var TagControl = /* @__PURE__ */ ((TagControl2) => {
  TagControl2[TagControl2["Anonymous"] = 0] = "Anonymous";
  TagControl2[TagControl2["ContextSpecific"] = 1] = "ContextSpecific";
  TagControl2[TagControl2["CommonProfile16"] = 2] = "CommonProfile16";
  TagControl2[TagControl2["CommonProfile32"] = 3] = "CommonProfile32";
  TagControl2[TagControl2["ImplicitProfile16"] = 4] = "ImplicitProfile16";
  TagControl2[TagControl2["ImplicitProfile32"] = 5] = "ImplicitProfile32";
  TagControl2[TagControl2["FullyQualified48"] = 6] = "FullyQualified48";
  TagControl2[TagControl2["FullyQualified64"] = 7] = "FullyQualified64";
  return TagControl2;
})(TagControl || {});
const ControlByteSchema = BitmapSchema({
  typeLength: BitField(0, 5),
  tagControl: BitFieldEnum(5, 3)
});
const MATTER_COMMON_PROFILE = 0;
class TlvCodec {
  static getUIntTlvLength(value) {
    if (value <= UINT8_MAX) {
      return 0 /* OneByte */;
    } else if (value <= UINT16_MAX) {
      return 1 /* TwoBytes */;
    } else if (value <= UINT32_MAX) {
      return 2 /* FourBytes */;
    } else {
      return 3 /* EightBytes */;
    }
  }
  static getIntTlvLength(value) {
    if (value > 0) {
      if (value <= INT8_MAX) {
        return 0 /* OneByte */;
      } else if (value <= INT16_MAX) {
        return 1 /* TwoBytes */;
      } else if (value <= INT32_MAX) {
        return 2 /* FourBytes */;
      } else {
        return 3 /* EightBytes */;
      }
    } else {
      if (value >= INT8_MIN) {
        return 0 /* OneByte */;
      } else if (value >= INT16_MIN) {
        return 1 /* TwoBytes */;
      } else if (value >= INT32_MIN) {
        return 2 /* FourBytes */;
      } else {
        return 3 /* EightBytes */;
      }
    }
  }
  /** @see {@link MatterSpecification.v10.Core} § A.7 */
  static readTagType(reader) {
    const { tagControl, typeLength } = ControlByteSchema.decode(reader.readUInt8());
    return { tag: this.readTag(reader, tagControl), typeLength: this.parseTypeLength(typeLength) };
  }
  static readTag(reader, tagControl) {
    switch (tagControl) {
      case 0 /* Anonymous */:
        return void 0;
      case 1 /* ContextSpecific */:
        return { id: reader.readUInt8() };
      case 2 /* CommonProfile16 */:
        return { profile: MATTER_COMMON_PROFILE, id: reader.readUInt16() };
      case 3 /* CommonProfile32 */:
        return { profile: MATTER_COMMON_PROFILE, id: reader.readUInt32() };
      case 4 /* ImplicitProfile16 */:
      case 5 /* ImplicitProfile32 */:
        throw new NotImplementedError(`Unsupported implicit profile ${tagControl}`);
      case 6 /* FullyQualified48 */:
        return { profile: reader.readUInt32(), id: reader.readUInt16() };
      default:
        throw new NotImplementedError(`Unexpected tagControl ${tagControl}`);
    }
  }
  static parseTypeLength(typeLength) {
    const length = typeLength & 3;
    const type = typeLength & 252;
    switch (type) {
      case 12 /* Utf8String */:
      case 16 /* ByteString */:
      case 0 /* SignedInt */:
      case 4 /* UnsignedInt */:
        return { type, length };
      case 8 /* Boolean */:
        switch (length) {
          case 0 /* OneByte */:
            return { type, value: false };
          case 1 /* TwoBytes */:
            return { type, value: true };
          case 2 /* FourBytes */:
            return { type: 10 /* Float */, length };
          case 3 /* EightBytes */:
            return { type: 10 /* Float */, length };
          default:
            throw new UnexpectedDataError(`Unexpected Boolean length ${length}`);
        }
      default:
        return { type: typeLength };
    }
  }
  static readPrimitive(reader, typeLength) {
    switch (typeLength.type) {
      case 0 /* SignedInt */: {
        const length = typeLength.length;
        switch (length) {
          case 0 /* OneByte */:
            return reader.readInt8();
          case 1 /* TwoBytes */:
            return reader.readInt16();
          case 2 /* FourBytes */:
            return reader.readInt32();
          case 3 /* EightBytes */:
            return reader.readInt64();
          default:
            throw new UnexpectedDataError(`Unexpected SignedInt length ${length}`);
        }
      }
      case 4 /* UnsignedInt */: {
        const length = typeLength.length;
        switch (length) {
          case 0 /* OneByte */:
            return reader.readUInt8();
          case 1 /* TwoBytes */:
            return reader.readUInt16();
          case 2 /* FourBytes */:
            return reader.readUInt32();
          case 3 /* EightBytes */:
            return reader.readUInt64();
          default:
            throw new UnexpectedDataError(`Unexpected UnsignedInt length ${length}`);
        }
      }
      case 10 /* Float */: {
        const length = typeLength.length;
        switch (length) {
          case 2 /* FourBytes */:
            return reader.readFloat();
          case 3 /* EightBytes */:
            return reader.readDouble();
          default:
            throw new UnexpectedDataError(`Unexpected Float length ${length}`);
        }
      }
      case 12 /* Utf8String */: {
        const length = typeLength.length;
        switch (length) {
          case 0 /* OneByte */:
            return reader.readUtf8String(reader.readUInt8());
          case 1 /* TwoBytes */:
            return reader.readUtf8String(reader.readUInt16());
          case 2 /* FourBytes */:
            return reader.readUtf8String(reader.readUInt32());
          case 3 /* EightBytes */:
            return reader.readUtf8String(Number(reader.readUInt64()));
          default:
            throw new UnexpectedDataError(`Unexpected Utf8String length ${length}`);
        }
      }
      case 16 /* ByteString */: {
        const length = typeLength.length;
        switch (length) {
          case 0 /* OneByte */:
            return reader.readByteArray(reader.readUInt8());
          case 1 /* TwoBytes */:
            return reader.readByteArray(reader.readUInt16());
          case 2 /* FourBytes */:
            return reader.readByteArray(reader.readUInt32());
          case 3 /* EightBytes */:
            return reader.readByteArray(Number(reader.readUInt64()));
          default:
            throw new UnexpectedDataError(`Unexpected ByteString length ${length}`);
        }
      }
      case 8 /* Boolean */:
        return typeLength.value;
      case 20 /* Null */:
        return null;
      default:
        throw new UnexpectedDataError(`Unexpected TLV type ${typeLength.type}`);
    }
  }
  /** @see {@link MatterSpecification.v10.Core} § A.7 & A.8 */
  static writeTag(writer, typeLengthValue, tag) {
    const { profile, id } = tag ?? {};
    let typeLength;
    switch (typeLengthValue.type) {
      case 12 /* Utf8String */:
      case 16 /* ByteString */:
      case 0 /* SignedInt */:
      case 4 /* UnsignedInt */:
      case 10 /* Float */:
        typeLength = typeLengthValue.type | typeLengthValue.length;
        break;
      case 8 /* Boolean */:
        typeLength = typeLengthValue.type + (typeLengthValue.value ? 1 : 0);
        break;
      default:
        typeLength = typeLengthValue.type;
    }
    if (profile === void 0 && id === void 0) {
      writer.writeUInt8(ControlByteSchema.encode({ tagControl: 0 /* Anonymous */, typeLength }));
    } else if (profile === void 0) {
      if (id === void 0)
        throw new UnexpectedDataError("Invalid TLV tag: id should be defined for a context specific tag.");
      writer.writeUInt8(ControlByteSchema.encode({ tagControl: 1 /* ContextSpecific */, typeLength }));
      writer.writeUInt8(id);
    } else if (profile === MATTER_COMMON_PROFILE) {
      if (id === void 0)
        throw new UnexpectedDataError("Invalid TLV tag: id should be defined for a datatype profile.");
      if ((id & 4294901760) === 0) {
        writer.writeUInt8(ControlByteSchema.encode({ tagControl: 2 /* CommonProfile16 */, typeLength }));
        writer.writeUInt16(id);
      } else {
        writer.writeUInt8(ControlByteSchema.encode({ tagControl: 3 /* CommonProfile32 */, typeLength }));
        writer.writeUInt32(id);
      }
    } else {
      if (id === void 0)
        throw new UnexpectedDataError("Invalid TLV tag: id should be defined for a custom profile.");
      if ((id & 4294901760) === 0) {
        writer.writeUInt8(ControlByteSchema.encode({ tagControl: 6 /* FullyQualified48 */, typeLength }));
        writer.writeUInt32(profile);
        writer.writeUInt16(id);
      } else {
        writer.writeUInt8(ControlByteSchema.encode({ tagControl: 7 /* FullyQualified64 */, typeLength }));
        writer.writeUInt32(profile);
        writer.writeUInt32(id);
      }
    }
  }
  static getTagByteLength(tag) {
    const { profile, id } = tag ?? {};
    if (profile === void 0 && id === void 0) {
      return 1;
    } else if (profile === void 0) {
      if (id === void 0)
        throw new UnexpectedDataError("Invalid TLV tag: id should be defined for a context specific tag.");
      return 2;
    } else if (profile === MATTER_COMMON_PROFILE) {
      if (id === void 0)
        throw new UnexpectedDataError("Invalid TLV tag: id should be defined for a datatype profile.");
      if ((id & 4294901760) === 0) {
        return 3;
      } else {
        return 5;
      }
    } else {
      if (id === void 0)
        throw new UnexpectedDataError("Invalid TLV tag: id should be defined for a custom profile.");
      if ((id & 4294901760) === 0) {
        return 7;
      } else {
        return 9;
      }
    }
  }
  static writePrimitive(writer, typeLength, value) {
    switch (typeLength.type) {
      case 0 /* SignedInt */:
        return this.writeUInt(writer, typeLength.length, value);
      case 4 /* UnsignedInt */: {
        const length = typeLength.length;
        switch (length) {
          case 0 /* OneByte */:
            return writer.writeUInt8(value);
          case 1 /* TwoBytes */:
            return writer.writeUInt16(value);
          case 2 /* FourBytes */:
            return writer.writeUInt32(value);
          case 3 /* EightBytes */:
            return writer.writeUInt64(value);
          default:
            throw new UnexpectedDataError(`Unexpected UnsignedInt length ${length}`);
        }
      }
      case 10 /* Float */: {
        const length = typeLength.length;
        switch (length) {
          case 2 /* FourBytes */:
            return writer.writeFloat(value);
          case 3 /* EightBytes */:
            return writer.writeDouble(value);
          default:
            throw new UnexpectedDataError(`Unexpected Float length ${length}`);
        }
      }
      case 12 /* Utf8String */: {
        const string = value;
        const stringData = Bytes.fromString(string);
        this.writeUInt(writer, typeLength.length, stringData.byteLength);
        return writer.writeByteArray(stringData);
      }
      case 16 /* ByteString */: {
        const byteArray = value;
        this.writeUInt(writer, typeLength.length, byteArray.byteLength);
        return writer.writeByteArray(byteArray);
      }
      case 8 /* Boolean */:
        return;
      default:
        throw new UnexpectedDataError(`Unexpected TLV type ${typeLength.type}`);
    }
  }
  static getPrimitiveByteLength(typeLength, value) {
    switch (typeLength.type) {
      case 0 /* SignedInt */:
      case 4 /* UnsignedInt */:
      case 10 /* Float */:
        return this.getUIntByteLength(typeLength.length);
      case 12 /* Utf8String */: {
        const string = value;
        const stringData = Bytes.fromString(string);
        return this.getUIntByteLength(typeLength.length) + stringData.byteLength;
      }
      case 16 /* ByteString */: {
        const byteArray = value;
        return this.getUIntByteLength(typeLength.length) + byteArray.byteLength;
      }
      case 8 /* Boolean */:
        return 0;
      default:
        throw new UnexpectedDataError(`Unexpected TLV type ${typeLength.type}`);
    }
  }
  static writeUInt(writer, length, value) {
    switch (length) {
      case 0 /* OneByte */:
        return writer.writeInt8(value);
      case 1 /* TwoBytes */:
        return writer.writeInt16(value);
      case 2 /* FourBytes */:
        return writer.writeInt32(value);
      case 3 /* EightBytes */:
        return writer.writeInt64(value);
    }
  }
  static getUIntByteLength(length) {
    switch (length) {
      case 0 /* OneByte */:
        return 1;
      case 1 /* TwoBytes */:
        return 2;
      case 2 /* FourBytes */:
        return 4;
      case 3 /* EightBytes */:
        return 8;
    }
  }
}
export {
  TlvCodec,
  TlvLength,
  TlvType
};
//# sourceMappingURL=TlvCodec.js.map
