//! Wire envelope shared by every transport.

use serde::{Deserialize, Serialize};

use crate::{clock::Hlc, conversation::ConversationId, device::DeviceId, WIRE_VERSION};

/// What an envelope carries. Application bytes are opaque; handshake variants are MLS payloads.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum MessageKind {
    Application = 1,
    Commit = 2,
    Welcome = 3,
    Proposal = 4,
    KeyPackage = 5,
}

/// On-the-wire envelope. CBOR-encoded.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageEnvelope {
    pub v: u8,
    pub conversation_id: ConversationId,
    pub epoch: u64,
    pub kind: MessageKind,
    pub sender_device: DeviceId,
    pub seq: u64,
    pub hlc: Hlc,
    #[serde(with = "serde_bytes")]
    pub payload: Vec<u8>,
    pub content_hash: [u8; 32],
}

impl MessageEnvelope {
    pub fn new(
        conversation_id: ConversationId,
        epoch: u64,
        kind: MessageKind,
        sender_device: DeviceId,
        seq: u64,
        hlc: Hlc,
        payload: Vec<u8>,
    ) -> Self {
        let content_hash = {
            use sha2::{Digest, Sha256};
            let mut h = Sha256::new();
            h.update([kind as u8]);
            h.update(&payload);
            h.finalize().into()
        };
        Self {
            v: WIRE_VERSION,
            conversation_id,
            epoch,
            kind,
            sender_device,
            seq,
            hlc,
            payload,
            content_hash,
        }
    }
}

/// Application message handed to the host on receive.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IncomingMessage {
    pub conversation_id: ConversationId,
    pub sender_device: DeviceId,
    pub epoch: u64,
    pub hlc: Hlc,
    /// Application-defined plaintext.
    #[serde(with = "serde_bytes")]
    pub plaintext: Vec<u8>,
    pub content_hash: [u8; 32],
}

/// Application message handed to the SDK to send.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutgoingMessage {
    /// Application-defined plaintext.
    #[serde(with = "serde_bytes")]
    pub plaintext: Vec<u8>,
}
