

import 'dart:typed_data';
import 'package:msgpack_dart/msgpack_dart.dart';
import 'package:es_compression/lz4.dart';

final lz4Codec = Lz4Codec();


Uint8List packPacket({
  required int ver,
  required int cmd,
  required int seq,
  required int opcode,
  required Map<String, dynamic> payload,
}) {
  Uint8List payloadBytes = serialize(payload);
  bool isCompressed = false;

  if (payloadBytes.length >= 32) {
    final uncompressedSize = ByteData(4)
      ..setUint32(0, payloadBytes.length, Endian.big);

    final compressedData = lz4Codec.encode(payloadBytes);

    final builder = BytesBuilder();
    builder.add(uncompressedSize.buffer.asUint8List());
    builder.add(compressedData);
    payloadBytes = builder.toBytes();
    isCompressed = true;
  }

  final header = ByteData(10);
  header.setUint8(0, ver);
  header.setUint16(1, cmd, Endian.big);
  header.setUint8(3, seq);
  header.setUint16(4, opcode, Endian.big);

  int packedLen = payloadBytes.length;
  if (isCompressed) {
    packedLen |= (1 << 24);
  }
  header.setUint32(6, packedLen, Endian.big);

  final builder = BytesBuilder();
  builder.add(header.buffer.asUint8List());
  builder.add(payloadBytes);

  return builder.toBytes();
}


Map<String, dynamic>? unpackPacket(Uint8List data) {
  if (data.length < 10) {
    print("Ошибка распаковки: Пакет слишком короткий для заголовка.");
    return null;
  }

  final byteData = data.buffer.asByteData(
    data.offsetInBytes,
    data.lengthInBytes,
  );

  final ver = byteData.getUint8(0);
  final cmd = byteData.getUint16(1, Endian.big);
  final seq = byteData.getUint8(3);
  final opcode = byteData.getUint16(4, Endian.big);
  final packedLen = byteData.getUint32(6, Endian.big);

  final compFlag = packedLen >> 24;
  final payloadLength = packedLen & 0x00FFFFFF;

  if (data.length < 10 + payloadLength) {
    print(
      "Ошибка распаковки: Фактическая длина пакета (${data.length}) меньше заявленной (${10 + payloadLength}).",
    );
    return null;
  }

  Uint8List payloadBytes = data.sublist(10, 10 + payloadLength);

  if (compFlag != 0) {
    try {
      final compressedData = payloadBytes.sublist(4);



      payloadBytes = Uint8List.fromList(lz4Codec.decode(compressedData));
    } catch (e) {
      print("Ошибка распаковки LZ4: $e");
      return null;
    }
  }

  final dynamic payload = deserialize(payloadBytes);

  return {
    "ver": ver,
    "cmd": cmd,
    "seq": seq,
    "opcode": opcode,
    "payload": payload,
  };
}
