"""CBOR serialization for attestation chain records.

Uses canonical CBOR encoding (RFC 8949 §4.2) for deterministic hashing
and signing. Integer keys are used in CBOR maps for compactness.
"""

from __future__ import annotations

import hashlib

import cbor2

from soosef.federation.models import AttestationChainRecord, EntropyWitnesses


def _entropy_to_cbor_map(ew: EntropyWitnesses) -> dict:
    """Convert EntropyWitnesses to a CBOR-ready map with integer keys."""
    return {
        0: ew.sys_uptime,
        1: ew.fs_snapshot,
        2: ew.proc_entropy,
        3: ew.boot_id,
    }


def _cbor_map_to_entropy(m: dict) -> EntropyWitnesses:
    """Convert a CBOR map back to EntropyWitnesses."""
    return EntropyWitnesses(
        sys_uptime=m[0],
        fs_snapshot=m[1],
        proc_entropy=m[2],
        boot_id=m[3],
    )


def canonical_bytes(record: AttestationChainRecord) -> bytes:
    """Produce deterministic CBOR bytes for hashing and signing.

    Includes all fields except signature. This is the input to both
    Ed25519_Sign and SHA-256 for chain linking.
    """
    m = {
        0: record.version,
        1: record.record_id,
        2: record.chain_index,
        3: record.prev_hash,
        4: record.content_hash,
        5: record.content_type,
        6: record.metadata,
        7: record.claimed_ts,
        8: _entropy_to_cbor_map(record.entropy_witnesses) if record.entropy_witnesses else {},
        9: record.signer_pubkey,
    }
    return cbor2.dumps(m, canonical=True)  # type: ignore[no-any-return]


def compute_record_hash(record: AttestationChainRecord) -> bytes:
    """SHA-256 of canonical_bytes(record). Used as prev_hash in next record."""
    return hashlib.sha256(canonical_bytes(record)).digest()


def serialize_record(record: AttestationChainRecord) -> bytes:
    """Full CBOR serialization including signature. Used for storage."""
    m = {
        0: record.version,
        1: record.record_id,
        2: record.chain_index,
        3: record.prev_hash,
        4: record.content_hash,
        5: record.content_type,
        6: record.metadata,
        7: record.claimed_ts,
        8: _entropy_to_cbor_map(record.entropy_witnesses) if record.entropy_witnesses else {},
        9: record.signer_pubkey,
        10: record.signature,
    }
    return cbor2.dumps(m, canonical=True)  # type: ignore[no-any-return]


def deserialize_record(data: bytes) -> AttestationChainRecord:
    """Deserialize CBOR bytes to an AttestationChainRecord."""
    m = cbor2.loads(data)
    entropy_map = m.get(8, {})
    entropy = _cbor_map_to_entropy(entropy_map) if entropy_map else None
    return AttestationChainRecord(
        version=m[0],
        record_id=m[1],
        chain_index=m[2],
        prev_hash=m[3],
        content_hash=m[4],
        content_type=m[5],
        metadata=m.get(6, {}),
        claimed_ts=m.get(7, 0),
        entropy_witnesses=entropy,
        signer_pubkey=m.get(9, b""),
        signature=m.get(10, b""),
    )
