"""Tests for CBOR serialization of chain records."""

from __future__ import annotations

import hashlib

from soosef.federation.models import AttestationChainRecord, ChainState, EntropyWitnesses
from soosef.federation.serialization import (
    canonical_bytes,
    compute_record_hash,
    deserialize_record,
    serialize_record,
)


def _make_record(**overrides) -> AttestationChainRecord:
    """Create a minimal test record with sensible defaults."""
    defaults = {
        "version": 1,
        "record_id": b"\x01" * 16,
        "chain_index": 0,
        "prev_hash": ChainState.GENESIS_PREV_HASH,
        "content_hash": hashlib.sha256(b"test content").digest(),
        "content_type": "test/plain",
        "metadata": {},
        "claimed_ts": 1_700_000_000_000_000,
        "entropy_witnesses": EntropyWitnesses(
            sys_uptime=12345.678,
            fs_snapshot=b"\xab" * 16,
            proc_entropy=256,
            boot_id="test-boot-id",
        ),
        "signer_pubkey": b"\x02" * 32,
        "signature": b"\x03" * 64,
    }
    defaults.update(overrides)
    return AttestationChainRecord(**defaults)


def test_canonical_bytes_deterministic():
    """Same record always produces the same canonical bytes."""
    record = _make_record()
    b1 = canonical_bytes(record)
    b2 = canonical_bytes(record)
    assert b1 == b2


def test_canonical_bytes_excludes_signature():
    """Canonical bytes must not include the signature field."""
    record_a = _make_record(signature=b"\x03" * 64)
    record_b = _make_record(signature=b"\x04" * 64)
    assert canonical_bytes(record_a) == canonical_bytes(record_b)


def test_canonical_bytes_sensitive_to_content():
    """Different content_hash must produce different canonical bytes."""
    record_a = _make_record(content_hash=hashlib.sha256(b"a").digest())
    record_b = _make_record(content_hash=hashlib.sha256(b"b").digest())
    assert canonical_bytes(record_a) != canonical_bytes(record_b)


def test_serialize_deserialize_round_trip():
    """A record survives serialization and deserialization intact."""
    original = _make_record()
    data = serialize_record(original)
    restored = deserialize_record(data)

    assert restored.version == original.version
    assert restored.record_id == original.record_id
    assert restored.chain_index == original.chain_index
    assert restored.prev_hash == original.prev_hash
    assert restored.content_hash == original.content_hash
    assert restored.content_type == original.content_type
    assert restored.metadata == original.metadata
    assert restored.claimed_ts == original.claimed_ts
    assert restored.signer_pubkey == original.signer_pubkey
    assert restored.signature == original.signature

    # Entropy witnesses
    assert restored.entropy_witnesses is not None
    assert restored.entropy_witnesses.sys_uptime == original.entropy_witnesses.sys_uptime
    assert restored.entropy_witnesses.fs_snapshot == original.entropy_witnesses.fs_snapshot
    assert restored.entropy_witnesses.proc_entropy == original.entropy_witnesses.proc_entropy
    assert restored.entropy_witnesses.boot_id == original.entropy_witnesses.boot_id


def test_serialize_includes_signature():
    """Full serialization must include the signature."""
    record = _make_record(signature=b"\xaa" * 64)
    data = serialize_record(record)
    restored = deserialize_record(data)
    assert restored.signature == b"\xaa" * 64


def test_compute_record_hash():
    """Record hash is SHA-256 of canonical bytes."""
    record = _make_record()
    expected = hashlib.sha256(canonical_bytes(record)).digest()
    assert compute_record_hash(record) == expected


def test_record_hash_changes_with_content():
    """Different records produce different hashes."""
    a = _make_record(content_hash=hashlib.sha256(b"a").digest())
    b = _make_record(content_hash=hashlib.sha256(b"b").digest())
    assert compute_record_hash(a) != compute_record_hash(b)


def test_metadata_preserved():
    """Arbitrary metadata survives round-trip."""
    meta = {"backfilled": True, "caption": "test photo", "tags": ["evidence", "urgent"]}
    record = _make_record(metadata=meta)
    data = serialize_record(record)
    restored = deserialize_record(data)
    assert restored.metadata == meta


def test_empty_entropy_witnesses():
    """Record with no entropy witnesses round-trips correctly."""
    record = _make_record(entropy_witnesses=None)
    data = serialize_record(record)
    restored = deserialize_record(data)
    assert restored.entropy_witnesses is None
