//! Record type discriminator and serialization functions.
//!
//! Handles the 8-byte header format for record type identification
//! and provides serialization functions for all record types.

use crate::error::{IngestError, Result};
use stemedb_core::serde::serialize;
use stemedb_core::types::{Assertion, Epoch, Vote};

/// Record type discriminator.
///
/// This allows the worker to deserialize the correct type from the payload.
/// We use an 8-byte header to maintain rkyv alignment requirements.
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecordType {
    /// An assertion record.
    Assertion = 0,
    /// A vote record.
    Vote = 1,
    /// An epoch record.
    Epoch = 2,
}

/// Size of the record type header (8 bytes for alignment).
pub(super) const RECORD_HEADER_SIZE: usize = 8;

impl TryFrom<u8> for RecordType {
    type Error = IngestError;

    fn try_from(value: u8) -> Result<Self> {
        match value {
            0 => Ok(RecordType::Assertion),
            1 => Ok(RecordType::Vote),
            2 => Ok(RecordType::Epoch),
            _ => Err(IngestError::Serialization(format!("Unknown record type: {}", value))),
        }
    }
}

/// Serialize an assertion with its record type header.
///
/// Uses an 8-byte header to maintain rkyv alignment requirements.
pub fn serialize_assertion(assertion: &Assertion) -> Result<Vec<u8>> {
    let bytes = serialize(assertion).map_err(|e| IngestError::Serialization(e.to_string()))?;

    let mut payload = Vec::with_capacity(RECORD_HEADER_SIZE + bytes.len());
    // 8-byte header: [type, 0, 0, 0, 0, 0, 0, 0]
    payload.push(RecordType::Assertion as u8);
    payload.extend_from_slice(&[0u8; RECORD_HEADER_SIZE - 1]);
    payload.extend_from_slice(&bytes);
    Ok(payload)
}

/// Serialize a vote with its record type header.
pub fn serialize_vote(vote: &Vote) -> Result<Vec<u8>> {
    let bytes = serialize(vote).map_err(|e| IngestError::Serialization(e.to_string()))?;

    let mut payload = Vec::with_capacity(RECORD_HEADER_SIZE + bytes.len());
    payload.push(RecordType::Vote as u8);
    payload.extend_from_slice(&[0u8; RECORD_HEADER_SIZE - 1]);
    payload.extend_from_slice(&bytes);
    Ok(payload)
}

/// Serialize an epoch with its record type header.
pub fn serialize_epoch(epoch: &Epoch) -> Result<Vec<u8>> {
    let bytes = serialize(epoch).map_err(|e| IngestError::Serialization(e.to_string()))?;

    let mut payload = Vec::with_capacity(RECORD_HEADER_SIZE + bytes.len());
    payload.push(RecordType::Epoch as u8);
    payload.extend_from_slice(&[0u8; RECORD_HEADER_SIZE - 1]);
    payload.extend_from_slice(&bytes);
    Ok(payload)
}
