"""Tests for the tunnel frame protocol (pack/unpack)."""

from __future__ import annotations

import struct

import pytest

from cube_cloud.tunnel.relay import (
    CMD_CLOSE,
    CMD_CONNECT,
    CMD_CONNECTED,
    CMD_DATA,
    CMD_ERROR,
    HEADER_SIZE,
    pack_frame,
    unpack_frame,
)


class TestPackUnpack:
    """Round-trip tests for pack_frame / unpack_frame."""

    def test_roundtrip_connect(self):
        data = pack_frame(CMD_CONNECT, 1, b"myapp")
        cmd, sid, payload = unpack_frame(data)
        assert cmd == CMD_CONNECT
        assert sid == 1
        assert payload == b"myapp"

    def test_roundtrip_data(self):
        payload = b"\x00\xff" * 100
        data = pack_frame(CMD_DATA, 42, payload)
        cmd, sid, p = unpack_frame(data)
        assert cmd == CMD_DATA
        assert sid == 42
        assert p == payload

    def test_roundtrip_close_no_payload(self):
        data = pack_frame(CMD_CLOSE, 99)
        cmd, sid, p = unpack_frame(data)
        assert cmd == CMD_CLOSE
        assert sid == 99
        assert p == b""

    def test_roundtrip_error(self):
        msg = "something failed"
        data = pack_frame(CMD_ERROR, 7, msg.encode())
        cmd, sid, p = unpack_frame(data)
        assert cmd == CMD_ERROR
        assert sid == 7
        assert p.decode() == msg

    def test_roundtrip_connected(self):
        data = pack_frame(CMD_CONNECTED, 3)
        cmd, sid, p = unpack_frame(data)
        assert cmd == CMD_CONNECTED
        assert sid == 3


class TestUnpackErrors:
    """Edge cases for unpack_frame."""

    def test_too_short_raises(self):
        with pytest.raises(ValueError, match="too short"):
            unpack_frame(b"\x01\x02")

    def test_exactly_header_size(self):
        """A frame with just the header and no payload should work."""
        data = struct.pack("!BI", CMD_CLOSE, 5)
        assert len(data) == HEADER_SIZE
        cmd, sid, p = unpack_frame(data)
        assert cmd == CMD_CLOSE
        assert sid == 5
        assert p == b""

    def test_large_stream_id(self):
        """Stream IDs up to 2^32-1 should work."""
        big_id = 2**32 - 1
        data = pack_frame(CMD_DATA, big_id, b"x")
        cmd, sid, p = unpack_frame(data)
        assert sid == big_id


class TestConstants:
    """Verify protocol constants."""

    def test_header_size(self):
        assert HEADER_SIZE == 5

    def test_command_values(self):
        assert CMD_CONNECT == 0x01
        assert CMD_DATA == 0x02
        assert CMD_CLOSE == 0x03
        assert CMD_ERROR == 0x04
        assert CMD_CONNECTED == 0x05
