"""Unit tests for peerdrop/utils/framing.py."""

import struct

from peerdrop.utils.framing import length_prefix_pack, length_prefix_unpack


class TestLengthPrefixPack:
    def test_basic(self):
        data = b"hello"
        packed = length_prefix_pack(data)
        assert len(packed) == 4 + len(data)

    def test_header_is_big_endian(self):
        data = b"test"
        packed = length_prefix_pack(data)
        (length,) = struct.unpack(">I", packed[:4])
        assert length == len(data)

    def test_empty_data(self):
        packed = length_prefix_pack(b"")
        assert len(packed) == 4
        (length,) = struct.unpack(">I", packed[:4])
        assert length == 0

    def test_large_data(self):
        data = b"x" * 100000
        packed = length_prefix_pack(data)
        (length,) = struct.unpack(">I", packed[:4])
        assert length == 100000
        assert packed[4:] == data


class TestLengthPrefixUnpack:
    def test_basic(self):
        data = b"hello world"
        packed = length_prefix_pack(data)
        result = length_prefix_unpack(packed)
        assert result is not None
        msg, remaining = result
        assert msg == data
        assert remaining == b""

    def test_empty_buffer(self):
        assert length_prefix_unpack(b"") is None

    def test_incomplete_header(self):
        assert length_prefix_unpack(b"\x00") is None
        assert length_prefix_unpack(b"\x00\x00") is None
        assert length_prefix_unpack(b"\x00\x00\x00") is None

    def test_incomplete_payload(self):
        packed = length_prefix_pack(b"hello")
        assert length_prefix_unpack(packed[:6]) is None

    def test_multiple_messages(self):
        msg1 = length_prefix_pack(b"first")
        msg2 = length_prefix_pack(b"second")
        buffer = msg1 + msg2

        result = length_prefix_unpack(buffer)
        assert result is not None
        unpacked1, buffer = result
        assert unpacked1 == b"first"

        result = length_prefix_unpack(buffer)
        assert result is not None
        unpacked2, buffer = result
        assert unpacked2 == b"second"
        assert buffer == b""

    def test_remaining_bytes(self):
        msg = length_prefix_pack(b"data")
        extra = b"extra"
        result = length_prefix_unpack(msg + extra)
        assert result is not None
        unpacked, remaining = result
        assert unpacked == b"data"
        assert remaining == extra

    def test_header_only(self):
        assert length_prefix_unpack(struct.pack(">I", 10)) is None

    def test_roundtrip_various_sizes(self):
        for size in [0, 1, 127, 128, 255, 256, 1024, 65536]:
            data = b"z" * size
            packed = length_prefix_pack(data)
            result = length_prefix_unpack(packed)
            assert result is not None, f"Failed for size {size}"
            msg, remaining = result
            assert msg == data
            assert remaining == b""
