//! Field types, values, and the [`TraceField`] trait.
//!
//! This module defines the wire types used to encode event fields, along with
//! owned ([`FieldValue`]) and zero-copy ([`FieldValueRef`]) decoded
//! representations. The [`EventEncoder`] is the low-level writer passed to
//! derived `encode_fields` implementations.

use crate::codec::{MAX_TIMESTAMP_DELTA_NS, TAG_TIMESTAMP_RESET};
use std::io::{self, Write};

/// Wire type tags for field types.
///
/// The high bit (0x80) is reserved as an "optional" modifier. When set, the
/// field is preceded by a 1-byte presence prefix on the wire: `0x00` means
/// absent (decoded as [`FieldValueRef::None`]), `0x01` means present (followed
/// by the inner type's normal encoding). The inner type tag is `tag & 0x7F`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
#[repr(u8)]
pub enum FieldType {
    I64 = 1,
    F64 = 2,
    Bool = 3,
    String = 4,
    Bytes = 5,
    PooledStackFrames = 6,
    PooledString = 7,
    StackFrames = 8,
    Varint = 9,
    StringMap = 10,
    U8 = 11,
    U16 = 12,
    U32 = 13,
    DynamicList = 14,
    DynamicMap = 15,
    // Optional variants (inner tag | 0x80).
    OptionalI64 = 0x81,
    OptionalF64 = 0x82,
    OptionalBool = 0x83,
    OptionalString = 0x84,
    OptionalBytes = 0x85,
    OptionalPooledStackFrames = 0x86,
    OptionalPooledString = 0x87,
    OptionalStackFrames = 0x88,
    OptionalVarint = 0x89,
    OptionalStringMap = 0x8A,
    OptionalU8 = 0x8B,
    OptionalU16 = 0x8C,
    OptionalU32 = 0x8D,
    OptionalDynamicList = 0x8E,
    OptionalDynamicMap = 0x8F,
}

/// Newtype for stack frame addresses (leaf-first).
#[derive(Debug, Clone, PartialEq)]
pub struct StackFrames(pub Vec<u64>);

impl From<Vec<u64>> for StackFrames {
    fn from(v: Vec<u64>) -> Self {
        StackFrames(v)
    }
}

impl FromIterator<u64> for StackFrames {
    fn from_iter<I: IntoIterator<Item = u64>>(iter: I) -> Self {
        StackFrames(iter.into_iter().collect())
    }
}

impl std::ops::Deref for StackFrames {
    type Target = [u64];
    fn deref(&self) -> &[u64] {
        &self.0
    }
}

/// An interned string reference (pool ID). Created by [`Encoder::intern_string`](crate::encoder::Encoder::intern_string).
/// On the wire this is a `PooledString` (u32 LE).
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedString(pub(crate) u32);

#[cfg(feature = "serde")]
impl serde::Serialize for InternedString {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_u32(self.0)
    }
}

impl InternedString {
    /// Construct from a raw pool ID. Intended for building data from external
    /// sources (e.g. wire decoding outside the `Encoder`).
    pub const fn from_raw(id: u32) -> Self {
        Self(id)
    }

    /// Returns the underlying pool ID.
    pub const fn raw_id(self) -> u32 {
        self.0
    }
}

impl std::fmt::Debug for InternedString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "pool#{}", self.0)
    }
}

/// An interned stack-frame reference (pool ID).
/// On the wire this is a `PooledStackFrames` (u32 LE).
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedStackFrames(pub(crate) u32);

#[cfg(feature = "serde")]
impl serde::Serialize for InternedStackFrames {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_u32(self.0)
    }
}

impl InternedStackFrames {
    /// Construct from a raw pool ID. Intended for building data from external
    /// sources (e.g. wire decoding outside the `Encoder`).
    pub const fn from_raw(id: u32) -> Self {
        Self(id)
    }

    /// Returns the underlying pool ID.
    pub const fn raw_id(self) -> u32 {
        self.0
    }
}

impl std::fmt::Debug for InternedStackFrames {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "stack#{}", self.0)
    }
}

/// Owned field value. Decoded from the wire format.
///
/// Note: `U8`, `U16`, and `U32` wire types are decoded into `Varint(v as u64)`.
/// The original fixed-width type is not preserved — use the schema's `FieldType`
/// if you need to distinguish them.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum FieldValue {
    I64(i64),
    F64(f64),
    Bool(bool),
    String(String),
    Bytes(Vec<u8>),
    PooledString(InternedString),
    StackFrames(StackFrames),
    PooledStackFrames(InternedStackFrames),
    Varint(u64),
    StringMap(Vec<(Vec<u8>, Vec<u8>)>),
    /// Self-describing list: each element carries its own type tag.
    List(Vec<FieldValue>),
    /// Self-describing map: each entry carries type tags for key and value.
    Map(Vec<(FieldValue, FieldValue)>),
    /// Absent optional field.
    None,
}

#[cfg(feature = "serde")]
impl serde::Serialize for FieldValue {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        match self {
            FieldValue::I64(v) => serializer.serialize_i64(*v),
            FieldValue::F64(v) => serializer.serialize_f64(*v),
            FieldValue::Bool(v) => serializer.serialize_bool(*v),
            FieldValue::String(v) => serializer.serialize_str(v),
            FieldValue::Bytes(v) => serializer.serialize_bytes(v),
            FieldValue::PooledString(id) => id.serialize(serializer),
            FieldValue::StackFrames(v) => v.0.serialize(serializer),
            FieldValue::PooledStackFrames(id) => id.serialize(serializer),
            FieldValue::Varint(v) => serializer.serialize_u64(*v),
            FieldValue::StringMap(pairs) => {
                use serde::ser::SerializeMap;
                let mut map = serializer.serialize_map(Some(pairs.len()))?;
                for (k, v) in pairs {
                    map.serialize_entry(
                        &std::string::String::from_utf8_lossy(k),
                        &std::string::String::from_utf8_lossy(v),
                    )?;
                }
                map.end()
            }
            FieldValue::List(items) => items.serialize(serializer),
            FieldValue::Map(pairs) => pairs.serialize(serializer),
            FieldValue::None => serializer.serialize_none(),
        }
    }
}

impl FieldValue {
    pub fn string(s: &str) -> Self {
        FieldValue::String(s.to_string())
    }

    /// Returns the `FieldType` wire tag corresponding to this value's type.
    /// Used for self-describing encoding in DynamicList/DynamicMap.
    pub fn field_type_tag(&self) -> u8 {
        match self {
            FieldValue::I64(_) => FieldType::I64 as u8,
            FieldValue::F64(_) => FieldType::F64 as u8,
            FieldValue::Bool(_) => FieldType::Bool as u8,
            FieldValue::String(_) => FieldType::String as u8,
            FieldValue::Bytes(_) => FieldType::Bytes as u8,
            FieldValue::PooledString(_) => FieldType::PooledString as u8,
            FieldValue::StackFrames(_) => FieldType::StackFrames as u8,
            FieldValue::PooledStackFrames(_) => FieldType::PooledStackFrames as u8,
            FieldValue::Varint(_) => FieldType::Varint as u8,
            FieldValue::StringMap(_) => FieldType::StringMap as u8,
            FieldValue::List(_) => FieldType::DynamicList as u8,
            FieldValue::Map(_) => FieldType::DynamicMap as u8,
            FieldValue::None => 0x00,
        }
    }
}

impl FieldType {
    /// The high bit used to mark a field type as optional on the wire.
    pub const OPTIONAL_BIT: u8 = 0x80;

    pub fn from_tag(tag: u8) -> Option<FieldType> {
        match tag {
            1 => Some(FieldType::I64),
            2 => Some(FieldType::F64),
            3 => Some(FieldType::Bool),
            4 => Some(FieldType::String),
            5 => Some(FieldType::Bytes),
            6 => Some(FieldType::PooledStackFrames),
            7 => Some(FieldType::PooledString),
            8 => Some(FieldType::StackFrames),
            9 => Some(FieldType::Varint),
            10 => Some(FieldType::StringMap),
            11 => Some(FieldType::U8),
            12 => Some(FieldType::U16),
            13 => Some(FieldType::U32),
            14 => Some(FieldType::DynamicList),
            15 => Some(FieldType::DynamicMap),
            0x81 => Some(FieldType::OptionalI64),
            0x82 => Some(FieldType::OptionalF64),
            0x83 => Some(FieldType::OptionalBool),
            0x84 => Some(FieldType::OptionalString),
            0x85 => Some(FieldType::OptionalBytes),
            0x86 => Some(FieldType::OptionalPooledStackFrames),
            0x87 => Some(FieldType::OptionalPooledString),
            0x88 => Some(FieldType::OptionalStackFrames),
            0x89 => Some(FieldType::OptionalVarint),
            0x8A => Some(FieldType::OptionalStringMap),
            0x8B => Some(FieldType::OptionalU8),
            0x8C => Some(FieldType::OptionalU16),
            0x8D => Some(FieldType::OptionalU32),
            0x8E => Some(FieldType::OptionalDynamicList),
            0x8F => Some(FieldType::OptionalDynamicMap),
            _ => None,
        }
    }

    /// Returns true if this is an optional field type.
    pub fn is_optional(self) -> bool {
        self as u8 & Self::OPTIONAL_BIT != 0
    }

    /// Returns the inner (non-optional) field type.
    pub fn inner(self) -> FieldType {
        FieldType::from_tag(self as u8 & 0x7F).unwrap_or(self)
    }
}

impl FieldValue {
    /// Encode this value into the writer.
    pub fn encode(&self, w: &mut impl Write) -> io::Result<()> {
        match self {
            FieldValue::I64(v) => w.write_all(&v.to_le_bytes()),
            FieldValue::F64(v) => w.write_all(&v.to_le_bytes()),
            FieldValue::Bool(v) => w.write_all(&[if *v { 1 } else { 0 }]),
            FieldValue::String(v) => {
                let bytes = v.as_bytes();
                w.write_all(&(bytes.len() as u32).to_le_bytes())?;
                w.write_all(bytes)
            }
            FieldValue::Bytes(v) => {
                w.write_all(&(v.len() as u32).to_le_bytes())?;
                w.write_all(v)
            }
            FieldValue::PooledString(id) => w.write_all(&id.0.to_le_bytes()),
            FieldValue::PooledStackFrames(id) => w.write_all(&id.0.to_le_bytes()),
            FieldValue::Varint(v) => crate::leb128::encode_unsigned(*v, w),
            FieldValue::StackFrames(addrs) => {
                w.write_all(&(addrs.len() as u32).to_le_bytes())?;
                for &addr in addrs.iter() {
                    w.write_all(&addr.to_le_bytes())?;
                }
                Ok(())
            }
            FieldValue::StringMap(pairs) => {
                w.write_all(&(pairs.len() as u32).to_le_bytes())?;
                for (k, v) in pairs {
                    w.write_all(&(k.len() as u32).to_le_bytes())?;
                    w.write_all(k)?;
                    w.write_all(&(v.len() as u32).to_le_bytes())?;
                    w.write_all(v)?;
                }
                Ok(())
            }
            FieldValue::List(items) => {
                w.write_all(&(items.len() as u32).to_le_bytes())?;
                for item in items {
                    w.write_all(&[item.field_type_tag()])?;
                    item.encode(w)?;
                }
                Ok(())
            }
            FieldValue::Map(pairs) => {
                w.write_all(&(pairs.len() as u32).to_le_bytes())?;
                for (k, v) in pairs {
                    w.write_all(&[k.field_type_tag()])?;
                    k.encode(w)?;
                    w.write_all(&[v.field_type_tag()])?;
                    v.encode(w)?;
                }
                Ok(())
            }
            FieldValue::None => {
                // Optional field absent: write the 0x00 prefix byte.
                w.write_all(&[0x00])
            }
        }
    }

    /// Decode a value of the given type from the buffer. Returns (value, remaining_slice).
    pub fn decode(field_type: FieldType, data: &[u8]) -> Option<(FieldValue, &[u8])> {
        match field_type {
            FieldType::I64 => {
                let v = i64::from_le_bytes(data.get(..8)?.try_into().ok()?);
                Some((FieldValue::I64(v), &data[8..]))
            }
            FieldType::F64 => {
                let v = f64::from_le_bytes(data.get(..8)?.try_into().ok()?);
                Some((FieldValue::F64(v), &data[8..]))
            }
            FieldType::Bool => Some((FieldValue::Bool(*data.first()? != 0), &data[1..])),
            FieldType::String => {
                let len = u32::from_le_bytes(data.get(..4)?.try_into().ok()?) as usize;
                let bytes = data.get(4..4 + len)?;
                let s = std::str::from_utf8(bytes)
                    .map(|s| s.to_string())
                    .unwrap_or_else(|_| {
                        // Spec requires UTF-8 but we don't want to silently drop the
                        // entire event. Replace invalid sequences so decoding can continue.
                        String::from_utf8_lossy(bytes).into_owned()
                    });
                Some((FieldValue::String(s), &data[4 + len..]))
            }
            FieldType::Bytes => {
                let len = u32::from_le_bytes(data.get(..4)?.try_into().ok()?) as usize;
                let bytes = data.get(4..4 + len)?.to_vec();
                Some((FieldValue::Bytes(bytes), &data[4 + len..]))
            }
            FieldType::PooledString => {
                let id = u32::from_le_bytes(data.get(..4)?.try_into().ok()?);
                Some((FieldValue::PooledString(InternedString(id)), &data[4..]))
            }
            FieldType::PooledStackFrames => {
                let id = u32::from_le_bytes(data.get(..4)?.try_into().ok()?);
                Some((
                    FieldValue::PooledStackFrames(InternedStackFrames(id)),
                    &data[4..],
                ))
            }
            FieldType::Varint => {
                let (v, consumed) = crate::leb128::decode_unsigned(data)?;
                Some((FieldValue::Varint(v), &data[consumed..]))
            }
            FieldType::U8 => Some((FieldValue::Varint(*data.first()? as u64), &data[1..])),
            FieldType::U16 => {
                let v = u16::from_le_bytes(data.get(..2)?.try_into().ok()?);
                Some((FieldValue::Varint(v as u64), &data[2..]))
            }
            FieldType::U32 => {
                let v = u32::from_le_bytes(data.get(..4)?.try_into().ok()?);
                Some((FieldValue::Varint(v as u64), &data[4..]))
            }
            FieldType::StackFrames => {
                let count = u32::from_le_bytes(data.get(..4)?.try_into().ok()?) as usize;
                let mut pos = 4;
                let mut addrs = Vec::with_capacity(count.min(data.len() / 8));
                for _ in 0..count {
                    let addr = u64::from_le_bytes(data.get(pos..pos + 8)?.try_into().ok()?);
                    addrs.push(addr);
                    pos += 8;
                }
                Some((FieldValue::StackFrames(addrs.into()), &data[pos..]))
            }
            FieldType::StringMap => {
                let count = u32::from_le_bytes(data.get(..4)?.try_into().ok()?) as usize;
                let mut pos = 4;
                let mut pairs = Vec::with_capacity(count.min(data.len() / 8));
                for _ in 0..count {
                    let klen =
                        u32::from_le_bytes(data.get(pos..pos + 4)?.try_into().ok()?) as usize;
                    pos += 4;
                    let k = data.get(pos..pos + klen)?.to_vec();
                    pos += klen;
                    let vlen =
                        u32::from_le_bytes(data.get(pos..pos + 4)?.try_into().ok()?) as usize;
                    pos += 4;
                    let v = data.get(pos..pos + vlen)?.to_vec();
                    pos += vlen;
                    pairs.push((k, v));
                }
                Some((FieldValue::StringMap(pairs), &data[pos..]))
            }
            FieldType::DynamicList | FieldType::OptionalDynamicList => {
                let count = u32::from_le_bytes(data.get(..4)?.try_into().ok()?) as usize;
                let mut pos = 4;
                let mut items = Vec::with_capacity(count.min(data.len() / 2));
                for _ in 0..count {
                    let tag = *data.get(pos)?;
                    pos += 1;
                    let ft = FieldType::from_tag(tag)?;
                    let (val, rest) = Self::decode(ft, &data[pos..])?;
                    pos += data.len() - pos - rest.len();
                    items.push(val);
                }
                Some((FieldValue::List(items), &data[pos..]))
            }
            FieldType::DynamicMap | FieldType::OptionalDynamicMap => {
                let count = u32::from_le_bytes(data.get(..4)?.try_into().ok()?) as usize;
                let mut pos = 4;
                let mut pairs = Vec::with_capacity(count.min(data.len() / 4));
                for _ in 0..count {
                    let key_tag = *data.get(pos)?;
                    pos += 1;
                    let key_ft = FieldType::from_tag(key_tag)?;
                    let (key, rest) = Self::decode(key_ft, &data[pos..])?;
                    pos += data.len() - pos - rest.len();

                    let val_tag = *data.get(pos)?;
                    pos += 1;
                    let val_ft = FieldType::from_tag(val_tag)?;
                    let (val, rest) = Self::decode(val_ft, &data[pos..])?;
                    pos += data.len() - pos - rest.len();

                    pairs.push((key, val));
                }
                Some((FieldValue::Map(pairs), &data[pos..]))
            }
            // Optional variants: decode using the inner type.
            _ => Self::decode(field_type.inner(), data),
        }
    }
}

/// Zero-copy field value that borrows from the input buffer.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum FieldValueRef<'a> {
    I64(i64),
    F64(f64),
    Bool(bool),
    String(&'a str),
    Bytes(&'a [u8]),
    PooledString(InternedString),
    /// Raw stack frame bytes. Use [`StackFramesRef::iter`] to iterate addresses.
    StackFrames(StackFramesRef<'a>),
    /// Reference to a stack-frame pool entry. Resolve via the decoder's stack pool.
    PooledStackFrames(InternedStackFrames),
    Varint(u64),
    StringMap(StringMapRef<'a>),
    /// Self-describing list. Use [`DynamicListRef::iter`] to access elements.
    List(DynamicListRef<'a>),
    /// Self-describing map. Use [`DynamicMapRef::iter`] to access entries.
    Map(DynamicMapRef<'a>),
    /// Absent optional field.
    None,
}

/// Zero-copy wrapper for delta-encoded stack frame data.
#[derive(Clone, PartialEq)]
pub struct StackFramesRef<'a> {
    data: &'a [u8],
    count: u32,
}

impl std::fmt::Debug for StackFramesRef<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let addrs: Vec<u64> = self.iter().collect();
        write!(f, "[")?;
        for (i, a) in addrs.iter().enumerate() {
            if i > 0 {
                write!(f, ", ")?;
            }
            write!(f, "0x{a:x}")?;
        }
        write!(f, "]")
    }
}

impl<'a> StackFramesRef<'a> {
    pub fn iter(&self) -> StackFrameIter<'a> {
        StackFrameIter::new(self.data, self.count)
    }

    pub fn count(&self) -> u32 {
        self.count
    }

    /// Raw packed bytes (u64 LE addresses). Used for zero-copy re-encoding.
    pub fn raw_data(&self) -> &'a [u8] {
        self.data
    }
}

/// Zero-copy wrapper for string map data.
#[derive(Debug, Clone, PartialEq)]
pub struct StringMapRef<'a> {
    data: &'a [u8],
    count: u32,
}

impl<'a> StringMapRef<'a> {
    pub fn iter(&self) -> StringMapIter<'a> {
        StringMapIter::new(self.data, self.count)
    }

    pub fn count(&self) -> u32 {
        self.count
    }

    /// Raw packed bytes (length-prefixed key-value pairs). Used for zero-copy re-encoding.
    pub fn raw_data(&self) -> &'a [u8] {
        self.data
    }
}

/// Opaque wrapper for a decoded dynamic list. Access elements via [`Self::iter`].
#[derive(Debug, Clone, PartialEq)]
pub struct DynamicListRef<'a>(Vec<FieldValueRef<'a>>);

impl<'a> DynamicListRef<'a> {
    /// Iterate the list elements.
    pub fn iter(&self) -> impl Iterator<Item = &FieldValueRef<'a>> {
        self.0.iter()
    }

    /// Number of elements.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Whether the list is empty.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

/// Opaque wrapper for a decoded dynamic map. Access entries via [`Self::iter`].
#[derive(Debug, Clone, PartialEq)]
pub struct DynamicMapRef<'a>(Vec<(FieldValueRef<'a>, FieldValueRef<'a>)>);

impl<'a> DynamicMapRef<'a> {
    /// Iterate the map entries as `(key, value)` pairs.
    pub fn iter(&self) -> impl Iterator<Item = (&FieldValueRef<'a>, &FieldValueRef<'a>)> {
        self.0.iter().map(|(k, v)| (k, v))
    }

    /// Number of entries.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Whether the map is empty.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl<'a> FieldValueRef<'a> {
    /// Decode a value of the given type, borrowing from `data` at `offset`.
    /// Returns (value, bytes_consumed).
    pub fn decode(field_type: FieldType, data: &'a [u8], offset: usize) -> Option<(Self, usize)> {
        let d = &data[offset..];
        match field_type {
            FieldType::I64 => {
                let v = i64::from_le_bytes(d.get(..8)?.try_into().ok()?);
                Some((FieldValueRef::I64(v), 8))
            }
            FieldType::F64 => {
                let v = f64::from_le_bytes(d.get(..8)?.try_into().ok()?);
                Some((FieldValueRef::F64(v), 8))
            }
            FieldType::Bool => Some((FieldValueRef::Bool(*d.first()? != 0), 1)),
            FieldType::String => {
                let len = u32::from_le_bytes(d.get(..4)?.try_into().ok()?) as usize;
                let bytes = d.get(4..4 + len)?;
                let s = std::str::from_utf8(bytes).ok()?;
                Some((FieldValueRef::String(s), 4 + len))
            }
            FieldType::Bytes => {
                let len = u32::from_le_bytes(d.get(..4)?.try_into().ok()?) as usize;
                let bytes = d.get(4..4 + len)?;
                Some((FieldValueRef::Bytes(bytes), 4 + len))
            }
            FieldType::PooledString => {
                let id = u32::from_le_bytes(d.get(..4)?.try_into().ok()?);
                Some((FieldValueRef::PooledString(InternedString(id)), 4))
            }
            FieldType::PooledStackFrames => {
                let id = u32::from_le_bytes(d.get(..4)?.try_into().ok()?);
                Some((FieldValueRef::PooledStackFrames(InternedStackFrames(id)), 4))
            }
            FieldType::Varint => {
                let (v, consumed) = crate::leb128::decode_unsigned(d)?;
                Some((FieldValueRef::Varint(v), consumed))
            }
            FieldType::U8 => Some((FieldValueRef::Varint(*d.first()? as u64), 1)),
            FieldType::U16 => {
                let v = u16::from_le_bytes(d.get(..2)?.try_into().ok()?);
                Some((FieldValueRef::Varint(v as u64), 2))
            }
            FieldType::U32 => {
                let v = u32::from_le_bytes(d.get(..4)?.try_into().ok()?);
                Some((FieldValueRef::Varint(v as u64), 4))
            }
            // StackFrames: scan to find end position, then wrap as zero-copy ref.
            FieldType::StackFrames => {
                let count = u32::from_le_bytes(d.get(..4)?.try_into().ok()?) as usize;
                let data_len = count * 8;
                let pos = 4 + data_len;
                d.get(4..pos)?; // bounds check
                Some((
                    FieldValueRef::StackFrames(StackFramesRef {
                        data: &d[4..pos],
                        count: count as u32,
                    }),
                    pos,
                ))
            }
            FieldType::StringMap => {
                let count = u32::from_le_bytes(d.get(..4)?.try_into().ok()?) as usize;
                let mut pos = 4;
                for _ in 0..count {
                    let klen = u32::from_le_bytes(d.get(pos..pos + 4)?.try_into().ok()?) as usize;
                    pos += 4 + klen;
                    let vlen = u32::from_le_bytes(d.get(pos..pos + 4)?.try_into().ok()?) as usize;
                    pos += 4 + vlen;
                }
                Some((
                    FieldValueRef::StringMap(StringMapRef {
                        data: &d[4..pos],
                        count: count as u32,
                    }),
                    pos,
                ))
            }
            FieldType::DynamicList | FieldType::OptionalDynamicList => {
                let count = u32::from_le_bytes(d.get(..4)?.try_into().ok()?) as usize;
                let mut pos = 4;
                let mut items = Vec::with_capacity(count.min(d.len() / 2));
                for _ in 0..count {
                    let tag = *d.get(pos)?;
                    pos += 1;
                    let ft = FieldType::from_tag(tag)?;
                    let (val, consumed) = Self::decode(ft, data, offset + pos)?;
                    pos += consumed;
                    items.push(val);
                }
                Some((FieldValueRef::List(DynamicListRef(items)), pos))
            }
            FieldType::DynamicMap | FieldType::OptionalDynamicMap => {
                let count = u32::from_le_bytes(d.get(..4)?.try_into().ok()?) as usize;
                let mut pos = 4;
                let mut pairs = Vec::with_capacity(count.min(d.len() / 4));
                for _ in 0..count {
                    let key_tag = *d.get(pos)?;
                    pos += 1;
                    let key_ft = FieldType::from_tag(key_tag)?;
                    let (key, key_consumed) = Self::decode(key_ft, data, offset + pos)?;
                    pos += key_consumed;

                    let val_tag = *d.get(pos)?;
                    pos += 1;
                    let val_ft = FieldType::from_tag(val_tag)?;
                    let (val, val_consumed) = Self::decode(val_ft, data, offset + pos)?;
                    pos += val_consumed;

                    pairs.push((key, val));
                }
                Some((FieldValueRef::Map(DynamicMapRef(pairs)), pos))
            }
            // Optional variants: decode using the inner type.
            _ => Self::decode(field_type.inner(), data, offset),
        }
    }

    /// Convert this zero-copy field value into an owned [`FieldValue`].
    pub fn to_owned(&self) -> FieldValue {
        match self {
            FieldValueRef::I64(v) => FieldValue::I64(*v),
            FieldValueRef::F64(v) => FieldValue::F64(*v),
            FieldValueRef::Bool(v) => FieldValue::Bool(*v),
            FieldValueRef::String(v) => FieldValue::String((*v).to_string()),
            FieldValueRef::Bytes(v) => FieldValue::Bytes(v.to_vec()),
            FieldValueRef::PooledString(id) => FieldValue::PooledString(*id),
            FieldValueRef::StackFrames(sf) => FieldValue::StackFrames(sf.iter().collect()),
            FieldValueRef::PooledStackFrames(id) => FieldValue::PooledStackFrames(*id),
            FieldValueRef::Varint(v) => FieldValue::Varint(*v),
            FieldValueRef::StringMap(sm) => FieldValue::StringMap(
                sm.iter()
                    .map(|(k, v)| (k.as_bytes().to_vec(), v.as_bytes().to_vec()))
                    .collect(),
            ),
            FieldValueRef::List(lr) => FieldValue::List(lr.iter().map(|v| v.to_owned()).collect()),
            FieldValueRef::Map(mr) => FieldValue::Map(
                mr.iter()
                    .map(|(k, v)| (k.to_owned(), v.to_owned()))
                    .collect(),
            ),
            FieldValueRef::None => FieldValue::None,
        }
    }
}

/// Iterator over stack frame addresses (u64 LE).
pub struct StackFrameIter<'a> {
    data: &'a [u8],
    pos: usize,
    remaining: u32,
}

impl<'a> StackFrameIter<'a> {
    pub fn new(data: &'a [u8], count: u32) -> Self {
        Self {
            data,
            pos: 0,
            remaining: count,
        }
    }
}

impl Iterator for StackFrameIter<'_> {
    type Item = u64;
    fn next(&mut self) -> Option<u64> {
        if self.remaining == 0 {
            return None;
        }
        let addr = u64::from_le_bytes(self.data.get(self.pos..self.pos + 8)?.try_into().ok()?);
        self.pos += 8;
        self.remaining -= 1;
        Some(addr)
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.remaining as usize, Some(self.remaining as usize))
    }
}

impl ExactSizeIterator for StackFrameIter<'_> {}

/// Iterator over zero-copy string map key-value pairs.
pub struct StringMapIter<'a> {
    data: &'a [u8],
    pos: usize,
    remaining: u32,
}

impl<'a> StringMapIter<'a> {
    pub fn new(data: &'a [u8], count: u32) -> Self {
        Self {
            data,
            pos: 0,
            remaining: count,
        }
    }
}

impl<'a> Iterator for StringMapIter<'a> {
    type Item = (&'a str, &'a str);
    fn next(&mut self) -> Option<Self::Item> {
        if self.remaining == 0 {
            return None;
        }
        let klen =
            u32::from_le_bytes(self.data.get(self.pos..self.pos + 4)?.try_into().ok()?) as usize;
        self.pos += 4;
        let k = std::str::from_utf8(self.data.get(self.pos..self.pos + klen)?).ok()?;
        self.pos += klen;
        let vlen =
            u32::from_le_bytes(self.data.get(self.pos..self.pos + 4)?.try_into().ok()?) as usize;
        self.pos += 4;
        let v = std::str::from_utf8(self.data.get(self.pos..self.pos + vlen)?).ok()?;
        self.pos += vlen;
        self.remaining -= 1;
        Some((k, v))
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.remaining as usize, Some(self.remaining as usize))
    }
}

impl ExactSizeIterator for StringMapIter<'_> {}

/// A writer wrapper that counts bytes written through it.
pub(crate) struct CountingWriter<W> {
    inner: W,
    bytes_written: u64,
}

impl<W> CountingWriter<W> {
    pub fn new(inner: W) -> Self {
        Self {
            inner,
            bytes_written: 0,
        }
    }

    pub fn bytes_written(&self) -> u64 {
        self.bytes_written
    }

    pub fn into_inner(self) -> W {
        self.inner
    }

    pub fn inner(&self) -> &W {
        &self.inner
    }
}

impl<W: Write> Write for CountingWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = self.inner.write(buf)?;
        self.bytes_written += n as u64;
        Ok(n)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.flush()
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.inner.write_all(buf)?;
        self.bytes_written += buf.len() as u64;
        Ok(())
    }
}

/// Encoding state: carries the output writer and timestamp base for delta encoding.
/// Used internally by [`EventEncoder`] and [`crate::encoder::Encoder`].
pub(crate) struct EncodeState<W: Write> {
    pub(crate) writer: CountingWriter<W>,
    /// Current timestamp base (set by TimestampReset frames).
    timestamp_base_ns: u64,
}

impl<W: Write> EncodeState<W> {
    pub fn new(writer: W) -> Self {
        Self {
            writer: CountingWriter::new(writer),
            timestamp_base_ns: 0,
        }
    }

    /// Explicitly override the timestamp base of this decoder.
    ///
    /// This function should only be used by internals that are attempting to partially resume an encoder
    /// on an already existing stream
    pub(crate) fn set_ts_base_unchecked(&mut self, new_base: u64) {
        self.timestamp_base_ns = new_base;
    }

    /// Compute the timestamp delta, emitting a TimestampReset frame if needed
    /// (delta overflow or backwards timestamp).
    ///
    /// The base advances to `ts_ns` after every event so that consecutive
    /// inter-event deltas stay small — critical for gzip compressibility.
    pub(crate) fn encode_timestamp_delta(&mut self, ts_ns: u64) -> io::Result<u32> {
        if ts_ns < self.timestamp_base_ns || ts_ns - self.timestamp_base_ns > MAX_TIMESTAMP_DELTA_NS
        {
            self.writer.write_all(&[TAG_TIMESTAMP_RESET])?;
            self.writer.write_all(&ts_ns.to_le_bytes())?;
            self.timestamp_base_ns = ts_ns;
            Ok(0)
        } else {
            let delta = (ts_ns - self.timestamp_base_ns) as u32;
            self.timestamp_base_ns = ts_ns;
            Ok(delta)
        }
    }
}

/// Short-lived encoder for writing the fields of a single event.
/// Created by [`crate::encoder::Encoder::write`] and passed to
/// [`crate::TraceEvent::encode_fields`], analogous to `fmt::Formatter`.
pub struct EventEncoder<'a, W: Write = Vec<u8>> {
    pub(crate) state: &'a mut EncodeState<W>,
}

impl<'a, W: Write> EventEncoder<'a, W> {
    pub(crate) fn new(state: &'a mut EncodeState<W>) -> Self {
        Self { state }
    }

    pub fn write_u8(&mut self, v: u8) -> io::Result<()> {
        self.state.writer.write_all(&[v])
    }

    pub fn write_u16(&mut self, v: u16) -> io::Result<()> {
        self.state.writer.write_all(&v.to_le_bytes())
    }

    pub fn write_u32(&mut self, v: u32) -> io::Result<()> {
        self.state.writer.write_all(&v.to_le_bytes())
    }

    pub fn write_u64(&mut self, v: u64) -> io::Result<()> {
        crate::leb128::encode_unsigned(v, &mut self.state.writer)
    }

    pub fn write_i64(&mut self, v: i64) -> io::Result<()> {
        self.state.writer.write_all(&v.to_le_bytes())
    }

    pub fn write_f64(&mut self, v: f64) -> io::Result<()> {
        self.state.writer.write_all(&v.to_le_bytes())
    }

    pub fn write_bool(&mut self, v: bool) -> io::Result<()> {
        self.state.writer.write_all(&[if v { 1 } else { 0 }])
    }

    pub fn write_string(&mut self, v: &str) -> io::Result<()> {
        let bytes = v.as_bytes();
        self.state
            .writer
            .write_all(&(bytes.len() as u32).to_le_bytes())?;
        self.state.writer.write_all(bytes)
    }

    pub fn write_bytes(&mut self, v: &[u8]) -> io::Result<()> {
        self.state
            .writer
            .write_all(&(v.len() as u32).to_le_bytes())?;
        self.state.writer.write_all(v)
    }

    pub fn write_interned(&mut self, v: InternedString) -> io::Result<()> {
        self.state.writer.write_all(&v.0.to_le_bytes())
    }

    pub fn write_interned_stack_frames(&mut self, v: InternedStackFrames) -> io::Result<()> {
        self.state.writer.write_all(&v.0.to_le_bytes())
    }

    pub fn write_stack_frames(&mut self, v: &StackFrames) -> io::Result<()> {
        self.state
            .writer
            .write_all(&(v.len() as u32).to_le_bytes())?;
        for &addr in v.iter() {
            self.state.writer.write_all(&addr.to_le_bytes())?;
        }
        Ok(())
    }

    pub fn write_string_map(&mut self, v: &[(String, String)]) -> io::Result<()> {
        self.state
            .writer
            .write_all(&(v.len() as u32).to_le_bytes())?;
        for (k, val) in v {
            let kb = k.as_bytes();
            self.state
                .writer
                .write_all(&(kb.len() as u32).to_le_bytes())?;
            self.state.writer.write_all(kb)?;
            let vb = val.as_bytes();
            self.state
                .writer
                .write_all(&(vb.len() as u32).to_le_bytes())?;
            self.state.writer.write_all(vb)?;
        }
        Ok(())
    }

    /// Write a [`FieldValue`] with its associated [`FieldType`].
    /// For optional field types, writes the presence prefix byte (`0x00` for
    /// `None`, `0x01` + inner encoding for present values).
    pub fn write_field_value(
        &mut self,
        value: &FieldValue,
        field_type: FieldType,
    ) -> io::Result<()> {
        if field_type.is_optional() {
            match value {
                FieldValue::None => return self.state.writer.write_all(&[0x00]),
                other => {
                    self.state.writer.write_all(&[0x01])?;
                    return other.encode(&mut self.state.writer);
                }
            }
        }
        value.encode(&mut self.state.writer)
    }
}

/// Trait for types that can be used as trace fields.
/// Provides schema metadata (`field_type`), encoding (`encode`), and
/// decoding (`decode_ref`).
pub trait TraceField {
    /// The zero-copy decoded form of this field.
    type Ref<'a>;

    fn field_type() -> FieldType;
    /// Whether this field is optional on the wire (high-bit modifier).
    fn is_optional() -> bool {
        false
    }
    /// Encode this field's value into the event encoder.
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()>;
    /// Extract this field's value from a zero-copy FieldValueRef.
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>>;
    /// Called when the field is absent from the wire data (not in the schema).
    /// Returns `None` for required fields (decode failure) and `Some(None)` for
    /// optional fields.
    fn decode_missing<'a>() -> Option<Self::Ref<'a>> {
        None
    }
}

impl TraceField for u8 {
    type Ref<'a> = u8;
    fn field_type() -> FieldType {
        FieldType::U8
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_u8(*self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::Varint(v) => Some(*v as u8),
            _ => None,
        }
    }
}

impl TraceField for u16 {
    type Ref<'a> = u16;
    fn field_type() -> FieldType {
        FieldType::U16
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_u16(*self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::Varint(v) => Some(*v as u16),
            _ => None,
        }
    }
}

impl TraceField for u32 {
    type Ref<'a> = u32;
    fn field_type() -> FieldType {
        FieldType::U32
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_u32(*self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::Varint(v) => Some(*v as u32),
            _ => None,
        }
    }
}

impl TraceField for u64 {
    type Ref<'a> = u64;
    fn field_type() -> FieldType {
        FieldType::Varint
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_u64(*self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::Varint(v) => Some(*v),
            _ => None,
        }
    }
}

impl TraceField for i64 {
    type Ref<'a> = i64;
    fn field_type() -> FieldType {
        FieldType::I64
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_i64(*self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::I64(v) => Some(*v),
            _ => None,
        }
    }
}

impl TraceField for f64 {
    type Ref<'a> = f64;
    fn field_type() -> FieldType {
        FieldType::F64
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_f64(*self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::F64(v) => Some(*v),
            _ => None,
        }
    }
}

impl TraceField for bool {
    type Ref<'a> = bool;
    fn field_type() -> FieldType {
        FieldType::Bool
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_bool(*self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::Bool(v) => Some(*v),
            _ => None,
        }
    }
}

impl TraceField for String {
    type Ref<'a> = &'a str;
    fn field_type() -> FieldType {
        FieldType::String
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_string(self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::String(s) => Some(s),
            _ => None,
        }
    }
}

impl TraceField for Vec<u8> {
    type Ref<'a> = &'a [u8];
    fn field_type() -> FieldType {
        FieldType::Bytes
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_bytes(self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::Bytes(b) => Some(b),
            _ => None,
        }
    }
}

impl TraceField for StackFrames {
    type Ref<'a> = StackFramesRef<'a>;
    fn field_type() -> FieldType {
        FieldType::StackFrames
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_stack_frames(self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::StackFrames(r) => Some(r.clone()),
            _ => None,
        }
    }
}

impl TraceField for InternedString {
    type Ref<'a> = InternedString;
    fn field_type() -> FieldType {
        FieldType::PooledString
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_interned(*self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::PooledString(id) => Some(*id),
            _ => None,
        }
    }
}

impl TraceField for InternedStackFrames {
    type Ref<'a> = InternedStackFrames;
    fn field_type() -> FieldType {
        FieldType::PooledStackFrames
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_interned_stack_frames(*self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::PooledStackFrames(id) => Some(*id),
            _ => None,
        }
    }
}

impl TraceField for Vec<(String, String)> {
    type Ref<'a> = StringMapRef<'a>;
    fn field_type() -> FieldType {
        FieldType::StringMap
    }
    fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
        enc.write_string_map(self)
    }
    fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
        match val {
            FieldValueRef::StringMap(r) => Some(r.clone()),
            _ => None,
        }
    }
}

// --- Optional field support ---

/// Blanket `TraceField` impl for `Option<T>` where `T: TraceField`.
///
/// On the wire, the field type tag has the high bit set (0x80 | inner_tag).
/// Encoding writes `0x00` for `None` or `0x01` followed by the inner value
/// for `Some`. Decoding maps `FieldValueRef::None` to `None` and delegates
/// to the inner type for present values.
macro_rules! impl_optional_trace_field {
    ($inner:ty) => {
        impl TraceField for Option<$inner> {
            type Ref<'a> = Option<<$inner as TraceField>::Ref<'a>>;

            fn field_type() -> FieldType {
                FieldType::from_tag(
                    <$inner as TraceField>::field_type() as u8 | FieldType::OPTIONAL_BIT,
                )
                .expect("no optional variant for inner type")
            }

            fn is_optional() -> bool {
                true
            }

            fn encode<W: Write>(&self, enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
                match self {
                    None => enc.state.writer.write_all(&[0x00]),
                    Some(v) => {
                        enc.state.writer.write_all(&[0x01])?;
                        <$inner as TraceField>::encode(v, enc)
                    }
                }
            }

            fn decode_ref<'a>(val: &FieldValueRef<'a>) -> Option<Self::Ref<'a>> {
                match val {
                    FieldValueRef::None => Some(None),
                    other => Some(Some(<$inner as TraceField>::decode_ref(other)?)),
                }
            }

            fn decode_missing<'a>() -> Option<Self::Ref<'a>> {
                Some(None)
            }
        }
    };
}

impl_optional_trace_field!(InternedString);
impl_optional_trace_field!(InternedStackFrames);
impl_optional_trace_field!(u8);
impl_optional_trace_field!(u16);
impl_optional_trace_field!(u32);
impl_optional_trace_field!(u64);
impl_optional_trace_field!(i64);
impl_optional_trace_field!(f64);
impl_optional_trace_field!(bool);
impl_optional_trace_field!(String);
impl_optional_trace_field!(Vec<u8>);
impl_optional_trace_field!(StackFrames);
impl_optional_trace_field!(Vec<(String, String)>);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn field_type_round_trip() {
        for tag in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13u8] {
            let ft = FieldType::from_tag(tag).unwrap();
            assert_eq!(ft as u8, tag);
        }
        assert!(FieldType::from_tag(0).is_none());
        assert!(FieldType::from_tag(14).is_some());
    }

    #[test]
    fn encode_decode_i64() {
        let val = FieldValue::I64(-123456789);
        let mut buf = Vec::new();
        val.encode(&mut buf).unwrap();
        let (decoded, _) = FieldValue::decode(FieldType::I64, &buf).unwrap();
        assert_eq!(decoded, val);
    }

    #[test]
    fn encode_decode_f64() {
        let val = FieldValue::F64(std::f64::consts::PI);
        let mut buf = Vec::new();
        val.encode(&mut buf).unwrap();
        let (decoded, _) = FieldValue::decode(FieldType::F64, &buf).unwrap();
        assert_eq!(decoded, val);
    }

    #[test]
    fn encode_decode_bool() {
        for b in [true, false] {
            let val = FieldValue::Bool(b);
            let mut buf = Vec::new();
            val.encode(&mut buf).unwrap();
            assert_eq!(buf.len(), 1);
            let (decoded, rest) = FieldValue::decode(FieldType::Bool, &buf).unwrap();
            assert!(rest.is_empty());
            assert_eq!(decoded, val);
        }
    }

    #[test]
    fn encode_decode_string() {
        let val = FieldValue::String("hello world".to_string());
        let mut buf = Vec::new();
        val.encode(&mut buf).unwrap();
        assert_eq!(buf.len(), 4 + 11);
        let (decoded, rest) = FieldValue::decode(FieldType::String, &buf).unwrap();
        assert!(rest.is_empty());
        assert_eq!(decoded, val);
    }

    #[test]
    fn encode_decode_bytes() {
        let val = FieldValue::Bytes(vec![0xff, 0x00, 0xab]);
        let mut buf = Vec::new();
        val.encode(&mut buf).unwrap();
        let (decoded, _) = FieldValue::decode(FieldType::Bytes, &buf).unwrap();
        assert_eq!(decoded, val);
    }

    #[test]
    fn encode_decode_pooled_string() {
        let val = FieldValue::PooledString(InternedString(42));
        let mut buf = Vec::new();
        val.encode(&mut buf).unwrap();
        assert_eq!(buf.len(), 4);
        let (decoded, _) = FieldValue::decode(FieldType::PooledString, &buf).unwrap();
        assert_eq!(decoded, val);
    }

    #[test]
    fn encode_decode_stack_frames() {
        let addrs = vec![
            0x5555_5555_1234u64,
            0x5555_5555_0a00,
            0x5555_5555_0800,
            0x5555_5555_0100,
        ];
        let val = FieldValue::StackFrames(addrs.clone().into());
        let mut buf = Vec::new();
        val.encode(&mut buf).unwrap();
        assert_eq!(buf.len(), 4 + 4 * 8); // count(4) + 4 raw u64s
        let (decoded, _) = FieldValue::decode(FieldType::StackFrames, &buf).unwrap();
        assert_eq!(decoded, val);
    }

    #[test]
    fn encode_decode_pooled_stack_frames() {
        let val = FieldValue::PooledStackFrames(InternedStackFrames(42));
        let mut buf = Vec::new();
        val.encode(&mut buf).unwrap();
        assert_eq!(buf.len(), 4);
        let (decoded, _) = FieldValue::decode(FieldType::PooledStackFrames, &buf).unwrap();
        assert_eq!(decoded, val);
    }

    #[test]
    fn encode_decode_varint_small() {
        let val = FieldValue::Varint(3);
        let mut buf = Vec::new();
        val.encode(&mut buf).unwrap();
        assert_eq!(buf.len(), 1);
        let (decoded, rest) = FieldValue::decode(FieldType::Varint, &buf).unwrap();
        assert!(rest.is_empty());
        assert_eq!(decoded, val);
    }

    #[test]
    fn encode_decode_varint_large() {
        let val = FieldValue::Varint(u64::MAX);
        let mut buf = Vec::new();
        val.encode(&mut buf).unwrap();
        assert_eq!(buf.len(), 10); // u64::MAX needs 10 LEB128 bytes
        let (decoded, rest) = FieldValue::decode(FieldType::Varint, &buf).unwrap();
        assert!(rest.is_empty());
        assert_eq!(decoded, val);
    }

    #[test]
    fn varint_poll_end_compactness() {
        // PollEnd: timestamp_ns=1_050_000, worker_id=3
        let mut buf = Vec::new();
        FieldValue::Varint(1_050_000).encode(&mut buf).unwrap();
        FieldValue::Varint(3).encode(&mut buf).unwrap();
        // timestamp ~3 bytes, worker 1 byte = ~4 bytes for the payload
        assert!(
            buf.len() <= 4,
            "PollEnd payload should be <=4 bytes, got {}",
            buf.len()
        );
    }
}
