//! The compact return profile — `extensions/bearer-receipts.md` §13: a reconciliation (§5) and a
//! holdings record (`extensions/holdings.md` §4) in a binary form for return paths whose messages
//! hold few bytes, carried in fragments with a check over the whole message.
//!
//! A compact record names by short references (§13.2) what its receiver already holds — the
//! group, the bearer instance, the signer — in a [`Context`]. [`expand`] turns it, against that
//! context, into the record's own bytes: a reconciliation claim's canonical form, a holdings
//! record's `WHD1`. [`encode`] is its inverse for a record that has a compact form (§13.5), and
//! refuses one that has none. The expansion is verified by the record's own text — `claim_receipt`
//! and bearer-receipts §5.3 for a reconciliation, [`crate::holdings`] for a holdings record — and
//! never here. [`cut`] and [`reassemble`] carry a message in fragments (§13.6, §13.7).
//!
//! # Rules enforced here rather than only documented
//!
//! - A reference resolves to one value or to none: two values with one reference refuse it
//!   (`compact_reference_ambiguous`), never resolved by choosing.
//! - A compact record has one reading and each form one spelling: a uint in its fewest bytes, a
//!   signer written inline with its own `did:key` is form 0 and never form 1, and a partial
//!   bitmap that sets every bit is the whole form's, so a reader refuses the other spelling.
//! - [`encode`] expands what it wrote against the same context and refuses unless that is the
//!   record it was given, byte for byte: what it returns round-trips.
//! - The check over a message is not a signature: whatever a message expands to is verified by
//!   its own signature, and the compact form carries no statement of its own.
//! - Fragments that are the same bytes are one fragment, so a fragment the path delivers twice is
//!   held once; two that differ at one index refuse the message (`fragment_repeated`).
//! - [`encode`] sizes nothing by a reconciliation's own `leaf_count` before it has found it to be
//!   the group's: a record received from a neighbour states it, and steps 1 and 2 bound it only by
//!   2^53 − 1.

use std::collections::BTreeSet;

use sha2::{Digest, Sha256};

use crate::claim_receipt::bearer::ATTESTS_RECEIVED;
use crate::claim_receipt::{rfc3339_seconds, rfc3339_utc, Bearer, ClaimBody, ClaimReceipt, ReconciliationClaim, SubjectType};
use crate::holdings::{self, Holdings};
use crate::jwp_delivery::{root as merkle_root, GroupReceipt, ObjectReceipt};
use crate::signer_id::did_key;

pub mod corpus;

/// The codes bearer-receipts §13.9 lists, in its order.
pub const CODES: &[&str] = &[
    MALFORMED,
    REFERENCE_UNKNOWN,
    REFERENCE_AMBIGUOUS,
    OBJECTS_NOT_HELD,
    NOT_ENCODABLE,
    FRAGMENT_MALFORMED,
    FRAGMENT_FOREIGN,
    FRAGMENT_REPEATED,
    FRAGMENT_MISSING,
    FRAGMENT_CHECK_FAILED,
];

pub const MALFORMED: &str = "compact_malformed";
pub const REFERENCE_UNKNOWN: &str = "compact_reference_unknown";
pub const REFERENCE_AMBIGUOUS: &str = "compact_reference_ambiguous";
pub const OBJECTS_NOT_HELD: &str = "compact_objects_not_held";
pub const NOT_ENCODABLE: &str = "compact_not_encodable";
pub const FRAGMENT_MALFORMED: &str = "fragment_malformed";
pub const FRAGMENT_FOREIGN: &str = "fragment_foreign";
pub const FRAGMENT_REPEATED: &str = "fragment_repeated";
pub const FRAGMENT_MISSING: &str = "fragment_missing";
pub const FRAGMENT_CHECK_FAILED: &str = "fragment_check_failed";

/// §13.3: a compact reconciliation's `kind`.
pub const KIND_RECONCILIATION: u8 = 0x01;
/// §13.4: a compact holdings record's `kind`.
pub const KIND_HOLDINGS: u8 = 0x02;
/// §13.6: the bytes of a fragment before its data.
pub const HEADER: usize = 3;
/// §13.1: the bytes of a message's check.
pub const CHECK: usize = 4;
/// §13.6: the most bytes a message has.
pub const MAX_MESSAGE: usize = 65_535;
/// §13.3, §13.4: the most bytes a compact record has, so that its message is at most
/// [`MAX_MESSAGE`].
pub const MAX_RECORD: usize = MAX_MESSAGE - CHECK;
/// §13.2: the greatest instant, 9999-12-31T23:59:59Z.
pub const MAX_SECONDS: u64 = 253_402_300_799;
/// §13.2: the greatest uint, 2^53 − 1.
pub const MAX_INT: u64 = (1 << 53) - 1;

// ───────────────────────────── §13.2 ─────────────────────────────

/// The first `N` bytes of SHA-256 over `bytes`: a reference (§13.2), and with `N` = 4 a
/// message's check (§13.1).
pub fn reference<const N: usize>(bytes: &[u8]) -> [u8; N] {
    Sha256::digest(bytes)[..N].try_into().expect("N is at most 32")
}

/// A group's reference: 8 bytes over its link hash.
pub fn group_ref(link_hash: &[u8; 32]) -> [u8; 8] {
    reference(link_hash)
}

/// A bearer instance's reference: 4 bytes over its `bearer_id` in UTF-8.
pub fn bearer_ref(bearer_id: &str) -> [u8; 4] {
    reference(bearer_id.as_bytes())
}

/// A signer's reference: 8 bytes over its key.
pub fn signer_ref(key: &[u8; 32]) -> [u8; 8] {
    reference(key)
}

/// A message's check (§13.1): the first 4 bytes of SHA-256 over its compact record.
pub fn check(record: &[u8]) -> [u8; CHECK] {
    reference(record)
}

/// Write `v` as a uint (§13.2): unsigned LEB128 in its fewest bytes.
pub fn put_uint(out: &mut Vec<u8>, mut v: u64) {
    loop {
        let b = (v & 0x7f) as u8;
        v >>= 7;
        if v == 0 {
            out.push(b);
            return;
        }
        out.push(b | 0x80);
    }
}

/// The instant of an `issued_at` (§13.2): seconds since 1970-01-01T00:00:00Z, for a text written
/// `YYYY-MM-DDTHH:MM:SSZ` with a second below 60 and at most [`MAX_SECONDS`]; `None` for any other
/// text, which has no instant.
pub fn instant_of(text: &str) -> Option<u64> {
    let s = u64::try_from(rfc3339_seconds(text)?).ok()?;
    (s <= MAX_SECONDS && rfc3339_utc(s) == text).then_some(s)
}

struct Reader<'a> {
    b: &'a [u8],
    at: usize,
}

impl<'a> Reader<'a> {
    fn take(&mut self, n: usize) -> Result<&'a [u8], &'static str> {
        let s = self.at.checked_add(n).and_then(|e| self.b.get(self.at..e)).ok_or(MALFORMED)?;
        self.at += n;
        Ok(s)
    }
    fn byte(&mut self) -> Result<u8, &'static str> {
        Ok(self.take(1)?[0])
    }
    fn array<const N: usize>(&mut self) -> Result<[u8; N], &'static str> {
        Ok(self.take(N)?.try_into().expect("N bytes"))
    }
    /// §13.2: a uint in its fewest bytes, at most 2^53 − 1, so at most 8 bytes.
    fn uint(&mut self) -> Result<u64, &'static str> {
        let mut v = 0u64;
        for i in 0..8 {
            let b = self.byte()?;
            v |= u64::from(b & 0x7f) << (7 * i);
            if b & 0x80 == 0 {
                return if (i > 0 && b == 0) || v > MAX_INT { Err(MALFORMED) } else { Ok(v) };
            }
        }
        Err(MALFORMED)
    }
    fn end(&self) -> Result<(), &'static str> {
        if self.at == self.b.len() {
            Ok(())
        } else {
            Err(MALFORMED)
        }
    }
}

// ───────────────────────────── §13.1: the context ─────────────────────────────

/// One group of a receiver's context (§13.1).
#[derive(Clone, Debug)]
pub struct ContextGroup {
    pub receipt: GroupReceipt,
    /// Its link hash, computed once.
    pub link: [u8; 32],
    /// The object receipts held under it that pass jwp-receipts §3 step 5 against it.
    pub objects: Vec<ObjectReceipt>,
    /// The `bearer_id` of each instance of the group the receiver holds a declaration of.
    pub bearers: Vec<String>,
}

/// A key a receiver holds, with its `signer_id` (§13.1).
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Signer {
    pub key: [u8; 32],
    pub signer_id: String,
}

/// What a receiver holds that a compact record names (§13.1).
#[derive(Clone, Debug, Default)]
pub struct Context {
    pub groups: Vec<ContextGroup>,
    pub signers: Vec<Signer>,
}

/// Of the values found under one reference, the one value they are, or why not (§13.2):
/// values with one key are one value.
fn one<T, K: Ord>(found: Vec<T>, key: impl Fn(&T) -> K) -> Result<T, &'static str> {
    let distinct: BTreeSet<K> = found.iter().map(key).collect();
    match distinct.len() {
        0 => Err(REFERENCE_UNKNOWN),
        1 => Ok(found.into_iter().next().expect("one value")),
        _ => Err(REFERENCE_AMBIGUOUS),
    }
}

impl Context {
    /// Add a group, with the object receipts and bearer instances held under it. A group whose
    /// receipt fails jwp-receipts §3 steps 1 and 2 is not held, nor is an object receipt that
    /// fails step 5 against it; a group already held gains the objects and instances.
    pub fn add_group(&mut self, receipt: GroupReceipt, objects: Vec<ObjectReceipt>, bearers: Vec<String>) {
        if receipt.verify().is_err() {
            return;
        }
        let objects: Vec<ObjectReceipt> = objects.into_iter().filter(|o| o.verify_inclusion(&receipt).is_ok()).collect();
        let link = receipt.link_hash();
        match self.groups.iter_mut().find(|g| g.link == link) {
            Some(g) => {
                g.objects.extend(objects);
                g.bearers.extend(bearers);
            }
            None => self.groups.push(ContextGroup { receipt, link, objects, bearers }),
        }
    }

    /// The group a reference resolves to.
    pub fn group(&self, r: &[u8; 8]) -> Result<&ContextGroup, &'static str> {
        one(self.groups.iter().filter(|g| group_ref(&g.link) == *r).collect(), |g| g.link)
    }

    /// The group whose link hash is `link`, if the context holds it.
    pub fn group_by_link(&self, link: &[u8; 32]) -> Option<&ContextGroup> {
        self.groups.iter().find(|g| g.link == *link)
    }

    /// The signer, key and `signer_id`, a reference resolves to: for a reconciliation.
    pub fn signer(&self, r: &[u8; 8]) -> Result<&Signer, &'static str> {
        one(self.signers.iter().filter(|s| signer_ref(&s.key) == *r).collect(), |s| (s.key, s.signer_id.clone()))
    }

    /// The key a reference resolves to: for a holdings record, which names no `signer_id`.
    pub fn key(&self, r: &[u8; 8]) -> Result<[u8; 32], &'static str> {
        one(self.signers.iter().filter(|s| signer_ref(&s.key) == *r).map(|s| s.key).collect(), |k| *k)
    }
}

impl ContextGroup {
    /// The bearer instance of this group a reference resolves to.
    pub fn bearer(&self, r: &[u8; 4]) -> Result<&str, &'static str> {
        one(self.bearers.iter().filter(|b| bearer_ref(b) == *r).collect(), |b| b.to_string()).map(|b| b.as_str())
    }
}

// ───────────────────────────── records ─────────────────────────────

/// A record in its own form: what a compact record expands to.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Record {
    /// A reconciliation claim's canonical form (jwp-receipts §2.4.3).
    Reconciliation(String),
    /// A holdings record's bytes (holdings §4).
    Holdings(Vec<u8>),
}

impl Record {
    pub fn bytes(&self) -> &[u8] {
        match self {
            Record::Reconciliation(s) => s.as_bytes(),
            Record::Holdings(b) => b,
        }
    }
}

/// §13.3, §13.4: a compact record, expanded against `ctx` into its record's own bytes.
pub fn expand(compact: &[u8], ctx: &Context) -> Result<Record, &'static str> {
    if compact.len() > MAX_RECORD {
        return Err(MALFORMED);
    }
    let mut r = Reader { b: compact, at: 0 };
    match r.byte()? {
        KIND_RECONCILIATION => expand_reconciliation(&mut r, ctx).map(Record::Reconciliation),
        KIND_HOLDINGS => expand_holdings(&mut r, ctx).map(Record::Holdings),
        _ => Err(MALFORMED),
    }
}

/// §13.5: a record's compact form against `ctx`, or `compact_not_encodable`.
pub fn encode(record: &Record, ctx: &Context) -> Result<Vec<u8>, &'static str> {
    let out = match record {
        Record::Reconciliation(text) => encode_reconciliation(text, ctx)?,
        Record::Holdings(bytes) => encode_holdings(bytes, ctx)?,
    };
    // What it wrote is the record's only if it expands to it, here and now.
    match expand(&out, ctx) {
        Ok(back) if back == *record => Ok(out),
        _ => Err(NOT_ENCODABLE),
    }
}

/// The bitmap of `leaf_count` objects that holds every one.
fn full_bitmap(leaf_count: u64) -> Vec<u8> {
    let mut b = vec![0xffu8; leaf_count.div_ceil(8) as usize];
    let used = (leaf_count % 8) as u32;
    if used != 0 {
        *b.last_mut().expect("a byte") = 0xffu8 << (8 - used);
    }
    b
}

/// §13.3: a partial `received`'s root, over the leaves of the object receipts the context holds
/// at its set bits, in increasing order.
fn received_root(g: &ContextGroup, received: &[u8]) -> Result<[u8; 32], &'static str> {
    let mut leaves = Vec::new();
    for i in 0..g.receipt.leaf_count {
        if received[(i / 8) as usize] & (0x80 >> (i % 8)) != 0 {
            let o = g.objects.iter().find(|o| o.object_id == i).ok_or(OBJECTS_NOT_HELD)?;
            leaves.push(o.leaf());
        }
    }
    Ok(merkle_root(&leaves))
}

fn expand_reconciliation(r: &mut Reader, ctx: &Context) -> Result<String, &'static str> {
    let form = r.byte()?;
    let bearer = match form & 0x03 {
        0 => Bearer::Bidirectional,
        1 => Bearer::Multicast,
        2 => Bearer::Unidirectional,
        _ => return Err(MALFORMED),
    };
    let whole = form & 0x04 != 0;
    let signer_form = (form >> 3) & 0x03;
    if form & 0xc0 != 0 || signer_form == 3 {
        return Err(MALFORMED);
    }
    let g = ctx.group(&r.array()?)?;
    let bearer_id = g.bearer(&r.array()?)?.to_string();
    let seq = r.uint()?;
    let issued_at = r.uint()?;
    if issued_at > MAX_SECONDS {
        return Err(MALFORMED);
    }
    let (signer_pubkey, signer_id) = match signer_form {
        0 => {
            let key: [u8; 32] = r.array()?;
            (key, did_key(&key))
        }
        1 => {
            let key: [u8; 32] = r.array()?;
            let n = usize::try_from(r.uint()?).map_err(|_| MALFORMED)?;
            let id = std::str::from_utf8(r.take(n)?).map_err(|_| MALFORMED)?.to_string();
            if id == did_key(&key) {
                return Err(MALFORMED);
            }
            (key, id)
        }
        _ => {
            let s = ctx.signer(&r.array()?)?;
            (s.key, s.signer_id.clone())
        }
    };
    let parent_receipt_hash = if form & 0x20 != 0 { Some(r.array::<32>()?) } else { None };
    let leaf_count = g.receipt.leaf_count;
    let received = if whole {
        full_bitmap(leaf_count)
    } else {
        let b = r.take(leaf_count.div_ceil(8) as usize)?.to_vec();
        let used = (leaf_count % 8) as u32;
        let past = used != 0 && b.last().is_some_and(|x| x & (0xffu8 >> used) != 0);
        if past || b.iter().all(|x| *x == 0) || b == full_bitmap(leaf_count) {
            return Err(MALFORMED);
        }
        b
    };
    let sig: [u8; 64] = r.array()?;
    r.end()?;
    let root = if whole { g.receipt.root_hash } else { received_root(g, &received)? };
    let claim = ClaimReceipt {
        subject_type: SubjectType::Receipt,
        subject: g.link,
        seq,
        issued_at: rfc3339_utc(issued_at),
        body: ClaimBody::Reconciliation(ReconciliationClaim {
            bearer,
            bearer_id,
            leaf_count,
            received,
            received_root: root,
            attests: ATTESTS_RECEIVED.into(),
        }),
        signer_pubkey,
        signer_id,
        parent_receipt_hash,
        sig,
        hybrid: None,
    };
    Ok(claim.to_json())
}

fn expand_holdings(r: &mut Reader, ctx: &Context) -> Result<Vec<u8>, &'static str> {
    let holder: [u8; 32] = match r.byte()? {
        0 => r.array()?,
        1 => ctx.key(&r.array()?)?,
        _ => return Err(MALFORMED),
    };
    let as_of_ms = r.uint()?;
    let window_ms = r.uint()?;
    let n = u32::try_from(r.uint()?).map_err(|_| MALFORMED)?;
    let mut out = Vec::new();
    out.extend_from_slice(holdings::MAGIC);
    out.push(1);
    out.extend_from_slice(&holder);
    out.extend_from_slice(&as_of_ms.to_be_bytes());
    out.extend_from_slice(&(as_of_ms + window_ms).to_be_bytes());
    out.extend_from_slice(&n.to_be_bytes());
    for _ in 0..n {
        let form = r.byte()?;
        if form & !0x03 != 0 {
            return Err(MALFORMED);
        }
        let (group, leaf_count) = if form & 0x02 != 0 {
            let g = ctx.group(&r.array()?)?;
            (g.link, g.receipt.leaf_count)
        } else {
            (r.array::<32>()?, r.uint()?)
        };
        out.extend_from_slice(&group);
        out.extend_from_slice(&leaf_count.to_be_bytes());
        if form & 0x01 != 0 {
            out.push(1);
        } else {
            out.push(0);
            out.extend_from_slice(r.take(leaf_count.div_ceil(8) as usize)?);
        }
    }
    out.extend_from_slice(&r.array::<64>()?);
    r.end()?;
    Ok(out)
}

fn encode_reconciliation(text: &str, ctx: &Context) -> Result<Vec<u8>, &'static str> {
    let no = Err(NOT_ENCODABLE);
    let Ok(c) = ClaimReceipt::from_json(text) else { return no };
    let ClaimBody::Reconciliation(b) = &c.body else { return no };
    if c.hybrid.is_some() || c.subject_type != SubjectType::Receipt || c.to_json() != text {
        return no;
    }
    let Some(g) = ctx.group_by_link(&c.subject) else { return no };
    let Some(issued_at) = instant_of(&c.issued_at) else { return no };
    // The claim's own leaf_count is the group's before anything is sized by it.
    if b.leaf_count != g.receipt.leaf_count {
        return no;
    }
    let whole = b.received == full_bitmap(g.receipt.leaf_count);
    let me = Signer { key: c.signer_pubkey, signer_id: c.signer_id.clone() };
    let signer_form = if ctx.signer(&signer_ref(&me.key)) == Ok(&me) {
        2
    } else if c.signer_id == did_key(&c.signer_pubkey) {
        0
    } else {
        1
    };
    let bearer: u8 = match b.bearer {
        Bearer::Bidirectional => 0,
        Bearer::Multicast => 1,
        Bearer::Unidirectional => 2,
    };
    let mut form = bearer | (signer_form << 3);
    if whole {
        form |= 0x04;
    }
    if c.parent_receipt_hash.is_some() {
        form |= 0x20;
    }
    let mut out = vec![KIND_RECONCILIATION, form];
    out.extend_from_slice(&group_ref(&g.link));
    out.extend_from_slice(&bearer_ref(&b.bearer_id));
    put_uint(&mut out, c.seq);
    put_uint(&mut out, issued_at);
    match signer_form {
        0 => out.extend_from_slice(&c.signer_pubkey),
        1 => {
            out.extend_from_slice(&c.signer_pubkey);
            put_uint(&mut out, c.signer_id.len() as u64);
            out.extend_from_slice(c.signer_id.as_bytes());
        }
        _ => out.extend_from_slice(&signer_ref(&c.signer_pubkey)),
    }
    if let Some(p) = &c.parent_receipt_hash {
        out.extend_from_slice(p);
    }
    if !whole {
        out.extend_from_slice(&b.received);
    }
    out.extend_from_slice(&c.sig);
    Ok(out)
}

fn encode_holdings(bytes: &[u8], ctx: &Context) -> Result<Vec<u8>, &'static str> {
    let h = Holdings::read(bytes).map_err(|_| NOT_ENCODABLE)?;
    let mut out = vec![KIND_HOLDINGS];
    if ctx.key(&signer_ref(&h.holder)) == Ok(h.holder) {
        out.push(1);
        out.extend_from_slice(&signer_ref(&h.holder));
    } else {
        out.push(0);
        out.extend_from_slice(&h.holder);
    }
    put_uint(&mut out, h.as_of_ms);
    put_uint(&mut out, h.expires_ms - h.as_of_ms);
    put_uint(&mut out, h.entries.len() as u64);
    for e in &h.entries {
        let by_ref = ctx.group(&group_ref(&e.group)).is_ok_and(|g| g.link == e.group && g.receipt.leaf_count == e.leaf_count);
        let whole = e.held == holdings::Held::Whole;
        out.push(u8::from(whole) | if by_ref { 0x02 } else { 0 });
        if by_ref {
            out.extend_from_slice(&group_ref(&e.group));
        } else {
            out.extend_from_slice(&e.group);
            put_uint(&mut out, e.leaf_count);
        }
        if let holdings::Held::Bitmap(bits) = &e.held {
            out.extend_from_slice(bits);
        }
    }
    out.extend_from_slice(&h.sig);
    Ok(out)
}

// ───────────────────────────── §13.6, §13.7: fragments ─────────────────────────────

/// A compact record followed by its check (§13.1).
pub fn message(record: &[u8]) -> Vec<u8> {
    [record, &check(record)[..]].concat()
}

/// §13.6: a compact record's message cut, in order, into fragments of `frame` bytes, the last
/// holding what remains, under the sender's number `number`. `None` when the path cannot carry
/// it: a frame below 4 bytes, a message over [`MAX_MESSAGE`], or one that needs more than 255
/// fragments.
pub fn cut(record: &[u8], number: u8, frame: usize) -> Option<Vec<Vec<u8>>> {
    let m = message(record);
    if frame <= HEADER || m.len() > MAX_MESSAGE {
        return None;
    }
    let chunks: Vec<&[u8]> = m.chunks(frame - HEADER).collect();
    let count = u8::try_from(chunks.len()).ok()?;
    Some(chunks.iter().enumerate().map(|(i, d)| [&[number, i as u8, count][..], d].concat()).collect())
}

/// §13.7: the compact record a message's fragments, in any order, carry; or the step that
/// refuses them.
pub fn reassemble(fragments: &[Vec<u8>]) -> Result<Vec<u8>, &'static str> {
    let first = fragments.first().ok_or(FRAGMENT_MISSING)?;
    if fragments.iter().any(|f| f.len() <= HEADER || f[2] == 0 || f[1] >= f[2]) {
        return Err(FRAGMENT_MALFORMED);
    }
    if fragments.iter().any(|f| f[0] != first[0] || f[2] != first[2]) {
        return Err(FRAGMENT_FOREIGN);
    }
    // Past step 2 every fragment has one number and one count, so two at one index with the same
    // data are the same bytes: one fragment.
    let mut slots: Vec<Option<&[u8]>> = vec![None; usize::from(first[2])];
    for f in fragments {
        let slot = &mut slots[usize::from(f[1])];
        match slot {
            Some(held) if *held == &f[HEADER..] => {}
            Some(_) => return Err(FRAGMENT_REPEATED),
            None => *slot = Some(&f[HEADER..]),
        }
    }
    let parts: Vec<&[u8]> = slots.into_iter().collect::<Option<_>>().ok_or(FRAGMENT_MISSING)?;
    let m = parts.concat();
    if m.len() > MAX_MESSAGE {
        return Err(FRAGMENT_MALFORMED);
    }
    if m.len() <= CHECK || m[m.len() - CHECK..] != check(&m[..m.len() - CHECK]) {
        return Err(FRAGMENT_CHECK_FAILED);
    }
    Ok(m[..m.len() - CHECK].to_vec())
}

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

    fn read_uint(b: &[u8]) -> Result<u64, &'static str> {
        let mut r = Reader { b, at: 0 };
        let v = r.uint()?;
        r.end().map(|()| v)
    }

    #[test]
    fn a_uint_has_one_spelling() {
        for v in [0, 1, 127, 128, 300, 16_383, 16_384, 1_793_692_800, MAX_INT] {
            let mut b = Vec::new();
            put_uint(&mut b, v);
            assert_eq!(read_uint(&b), Ok(v), "{v}");
        }
        assert_eq!(read_uint(&[0x80, 0x00]), Err(MALFORMED), "0 in two bytes");
        assert_eq!(read_uint(&[0xff, 0x00]), Err(MALFORMED), "127 in two bytes");
        assert_eq!(read_uint(&[0xff; 7].iter().copied().chain([0x0f]).collect::<Vec<_>>()), Ok(MAX_INT));
        assert_eq!(read_uint(&[0xff; 7].iter().copied().chain([0x10]).collect::<Vec<_>>()), Err(MALFORMED), "2^53");
        assert_eq!(read_uint(&[0x80; 8]), Err(MALFORMED), "a ninth byte");
        assert_eq!(read_uint(&[0x80]), Err(MALFORMED), "ends inside");
    }

    #[test]
    fn an_instant_is_one_spelling_of_one_second() {
        assert_eq!(instant_of("1970-01-01T00:00:00Z"), Some(0));
        assert_eq!(instant_of("2026-10-22T08:00:00Z"), Some(1_792_656_000));
        assert_eq!(instant_of("9999-12-31T23:59:59Z"), Some(MAX_SECONDS));
        for other in ["2026-10-22T08:00:00.0Z", "2026-10-22T08:00:00+00:00", "2026-10-22t08:00:00z", "2026-10-22T08:00:60Z", "1969-12-31T23:59:59Z"] {
            assert_eq!(instant_of(other), None, "{other}");
        }
        assert_eq!(rfc3339_utc(MAX_SECONDS), "9999-12-31T23:59:59Z");
    }

    #[test]
    fn the_full_bitmap_leaves_the_bits_past_the_group_clear() {
        assert_eq!(full_bitmap(1), vec![0x80]);
        assert_eq!(full_bitmap(8), vec![0xff]);
        assert_eq!(full_bitmap(9), vec![0xff, 0x80]);
        assert_eq!(full_bitmap(20), vec![0xff, 0xff, 0xf0]);
    }

    #[test]
    fn a_message_reassembles_in_any_order_and_each_defect_refuses() {
        let record: Vec<u8> = (0u8..40).collect();
        let f = cut(&record, 7, 11).expect("a frame of 11");
        assert_eq!(f.len(), 6, "44 bytes in pieces of 8");
        assert!(f.iter().all(|x| x.len() <= 11));
        assert_eq!(reassemble(&f), Ok(record.clone()));
        let mut back = f.clone();
        back.reverse();
        assert_eq!(reassemble(&back), Ok(record.clone()), "arrival order is free");
        assert_eq!(reassemble(&f[1..]), Err(FRAGMENT_MISSING));
        assert_eq!(reassemble(&[]), Err(FRAGMENT_MISSING));
        assert_eq!(reassemble(&[f.clone(), vec![f[2].clone()]].concat()), Ok(record.clone()), "a fragment twice, byte for byte, is one");
        let mut other_data = f[2].clone();
        other_data[HEADER] ^= 0x01;
        assert_eq!(reassemble(&[f.clone(), vec![other_data]].concat()), Err(FRAGMENT_REPEATED));
        let mut swapped = f.clone();
        let (a, b) = (swapped[1][HEADER..].to_vec(), swapped[2][HEADER..].to_vec());
        swapped[1].truncate(HEADER);
        swapped[1].extend_from_slice(&b);
        swapped[2].truncate(HEADER);
        swapped[2].extend_from_slice(&a);
        assert_eq!(reassemble(&swapped), Err(FRAGMENT_CHECK_FAILED), "two fragments' data exchanged");
        let other = cut(&[9u8; 40], 8, 11).expect("another");
        let mut foreign = f.clone();
        foreign[3] = other[3].clone();
        assert_eq!(reassemble(&foreign), Err(FRAGMENT_FOREIGN));
        let same_number = cut(&[9u8; 40], 7, 11).expect("another under the same number");
        let mut mixed = f.clone();
        mixed[3] = same_number[3].clone();
        assert_eq!(reassemble(&mixed), Err(FRAGMENT_CHECK_FAILED));
        assert_eq!(reassemble(&[vec![7, 0, 1]]), Err(FRAGMENT_MALFORMED), "no data");
        assert_eq!(reassemble(&[vec![7, 1, 1, 0]]), Err(FRAGMENT_MALFORMED), "index past count");
        assert_eq!(reassemble(&[vec![7, 0, 0, 0]]), Err(FRAGMENT_MALFORMED), "count 0");
        assert_eq!(reassemble(&[[&[7u8, 0, 1][..], &check(&[])].concat()]), Err(FRAGMENT_CHECK_FAILED), "a check with no record");
        assert!(cut(&record, 7, 3).is_none(), "a frame of the header alone");
        assert!(cut(&vec![0u8; 300], 7, 4).is_none(), "more than 255 fragments");
        // §13.6's bound: 255 fragments of 258 bytes of data hold more than 65,535 bytes.
        let big: Vec<Vec<u8>> = (0..255u8).map(|i| [&[7u8, i, 255][..], &[0u8; 258][..]].concat()).collect();
        assert_eq!(reassemble(&big), Err(FRAGMENT_MALFORMED));
        assert!(cut(&vec![0u8; MAX_RECORD], 7, 1500).is_some());
        assert!(cut(&vec![0u8; MAX_RECORD + 1], 7, 1500).is_none());
    }

    #[test]
    fn a_record_past_the_bound_is_refused_before_it_is_read() {
        let ctx = Context::default();
        assert_eq!(expand(&vec![KIND_HOLDINGS; MAX_RECORD + 1], &ctx), Err(MALFORMED));
        assert_eq!(expand(&[], &ctx), Err(MALFORMED));
        assert_eq!(expand(&[0x03], &ctx), Err(MALFORMED));
    }
}
