"""
Payload encoding/decoding for clawID watermarks.

Binary format:
  MAGIC(4) + VERSION(1) + COMPRESSED_LEN(2) + COMPRESSED_JSON(n) + CRC32(4)
"""

import json
import zlib
import struct
from binascii import crc32 as _crc32

MAGIC = b'CLWD'
VERSION = 1
HEADER_BYTES = 7  # MAGIC(4) + VERSION(1) + COMPRESSED_LEN(2)


def encode(metadata: dict) -> bytes:
    """Encode metadata dict to binary payload bytes."""
    json_bytes = json.dumps(metadata, separators=(',', ':')).encode('utf-8')
    compressed = zlib.compress(json_bytes, level=9)
    header = MAGIC + bytes([VERSION]) + struct.pack('>H', len(compressed))
    body = header + compressed
    checksum = struct.pack('>I', _crc32(body) & 0xFFFFFFFF)
    return body + checksum


def decode(data: bytes) -> dict:
    """Decode binary payload bytes back to metadata dict."""
    if len(data) < HEADER_BYTES + 4:
        raise ValueError("Payload too short")
    if data[:4] != MAGIC:
        raise ValueError("Invalid clawID magic bytes — not a clawID watermark")
    if data[4] != VERSION:
        raise ValueError(f"Unsupported watermark version: {data[4]}")

    compressed_len = struct.unpack('>H', data[5:7])[0]
    body_end = HEADER_BYTES + compressed_len
    body = data[:body_end]

    stored_crc = struct.unpack('>I', data[body_end:body_end + 4])[0]
    computed_crc = _crc32(body) & 0xFFFFFFFF
    if stored_crc != computed_crc:
        raise ValueError("Watermark corrupted (CRC mismatch)")

    return json.loads(zlib.decompress(data[HEADER_BYTES:body_end]).decode('utf-8'))


def to_bits(data: bytes) -> list:
    """Convert bytes to list of bits, MSB first."""
    return [(byte >> (7 - i)) & 1 for byte in data for i in range(8)]


def from_bits(bits: list) -> bytes:
    """Convert list of bits back to bytes (pads to multiple of 8)."""
    bits = list(bits) + [0] * ((-len(bits)) % 8)
    return bytes(
        sum(bits[i + j] << (7 - j) for j in range(8))
        for i in range(0, len(bits), 8)
    )
