//! Content-addressed identifier for operations.

use std::fmt;

use serde::{Deserialize, Serialize};

/// 32-byte blake3 content address of a canonically-encoded operation.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct OpId(pub [u8; 32]);

impl OpId {
    /// Hash canonical-encoded operation bytes into an `OpId`.
    pub fn from_bytes(bytes: &[u8]) -> Self {
        Self(*blake3::hash(bytes).as_bytes())
    }

    /// Lowercase hex representation (64 chars). Used in `Debug` and logs.
    pub fn to_hex(&self) -> String {
        let mut s = String::with_capacity(64);
        for byte in self.0 {
            use std::fmt::Write as _;
            let _ = write!(s, "{byte:02x}");
        }
        s
    }
}

impl fmt::Debug for OpId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "OpId({})", self.to_hex())
    }
}
