//! Gold Standard assertions for agent verification.
//!
//! A Gold Standard is a reference to an existing assertion that has been
//! verified as ground truth by administrators. When agents vote on or assert
//! claims that align with gold standards, their TrustRank increases.
//!
//! This creates a "proof of knowledge" mechanism that Sybil farms can't easily
//! game, since they must demonstrate understanding of verified facts.

use rkyv::{Archive, Deserialize, Serialize};

/// A gold standard is a reference to an existing assertion that has been
/// verified as ground truth by administrators.
///
/// Gold standards enable the "vote to see" exchange in the browser extension:
/// new agents must vote correctly on known truths to gain TrustRank and
/// unlock premium features.
///
/// # Storage
///
/// Stored at `GS:{subject}:{predicate}` to enable efficient lookups when
/// verifying agent submissions against known truths.
///
/// # Invariants
///
/// - `assertion_hash` must reference an existing assertion in the store
/// - `subject` and `predicate` must match the referenced assertion
/// - `expected_object` is the canonical "correct" answer
/// - Only administrators can create or remove gold standards
#[derive(Archive, Deserialize, Serialize, Debug, Clone, PartialEq)]
#[archive(check_bytes)]
pub struct GoldStandard {
    /// Hash of the verified assertion (BLAKE3, 32 bytes).
    pub assertion_hash: [u8; 32],

    /// Subject entity (e.g., "Earth", "Semaglutide").
    pub subject: String,

    /// Predicate/relation (e.g., "has_shape", "treats_condition").
    pub predicate: String,

    /// The canonical "correct" answer for this subject-predicate pair.
    /// This is what agents must vote for to demonstrate knowledge.
    pub expected_object: String,

    /// Unix timestamp when this gold standard was created (seconds).
    pub created_at: u64,

    /// Administrator identifier who created this gold standard.
    /// Could be a human username or an admin agent ID.
    pub created_by: String,
}

impl GoldStandard {
    /// Create a new GoldStandard.
    ///
    /// # Arguments
    ///
    /// - `assertion_hash` - Hash of the verified assertion
    /// - `subject` - Subject entity from the assertion
    /// - `predicate` - Predicate from the assertion
    /// - `expected_object` - The correct answer
    /// - `created_at` - Unix timestamp (seconds)
    /// - `created_by` - Administrator identifier
    pub fn new(
        assertion_hash: [u8; 32],
        subject: String,
        predicate: String,
        expected_object: String,
        created_at: u64,
        created_by: String,
    ) -> Self {
        Self { assertion_hash, subject, predicate, expected_object, created_at, created_by }
    }

    /// Check if an agent's answer matches this gold standard.
    ///
    /// **Case Sensitivity:** This comparison is **case-sensitive**. The agent's
    /// answer must match the expected object exactly, including case.
    ///
    /// # Arguments
    ///
    /// - `agent_answer` - The agent's proposed answer
    ///
    /// # Returns
    ///
    /// `true` if the agent's answer matches the expected object, `false` otherwise.
    ///
    /// # Example
    ///
    /// ```
    /// use stemedb_core::types::GoldStandard;
    ///
    /// let gs = GoldStandard::new(
    ///     [0u8; 32],
    ///     "Earth".to_string(),
    ///     "has_shape".to_string(),
    ///     "oblate_spheroid".to_string(),
    ///     1000,
    ///     "admin".to_string(),
    /// );
    ///
    /// assert!(gs.matches("oblate_spheroid"));
    /// assert!(!gs.matches("Oblate_Spheroid")); // case-sensitive
    /// ```
    pub fn matches(&self, agent_answer: &str) -> bool {
        self.expected_object == agent_answer
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::serde;

    #[test]
    fn test_gold_standard_creation() {
        let hash = [1u8; 32];
        let gs = GoldStandard::new(
            hash,
            "Earth".to_string(),
            "has_shape".to_string(),
            "oblate_spheroid".to_string(),
            1000,
            "admin_alice".to_string(),
        );

        assert_eq!(gs.assertion_hash, hash);
        assert_eq!(gs.subject, "Earth");
        assert_eq!(gs.predicate, "has_shape");
        assert_eq!(gs.expected_object, "oblate_spheroid");
        assert_eq!(gs.created_at, 1000);
        assert_eq!(gs.created_by, "admin_alice");
    }

    #[test]
    fn test_gold_standard_matches() {
        let gs = GoldStandard::new(
            [0u8; 32],
            "Earth".to_string(),
            "has_shape".to_string(),
            "oblate_spheroid".to_string(),
            1000,
            "admin".to_string(),
        );

        assert!(gs.matches("oblate_spheroid"));
        assert!(!gs.matches("flat"));
        assert!(!gs.matches("sphere"));
    }

    #[test]
    fn test_gold_standard_case_sensitive() {
        let gs = GoldStandard::new(
            [0u8; 32],
            "Earth".to_string(),
            "has_shape".to_string(),
            "oblate_spheroid".to_string(),
            1000,
            "admin".to_string(),
        );

        // Case-sensitive matching
        assert!(gs.matches("oblate_spheroid"));
        assert!(!gs.matches("Oblate_Spheroid"));
        assert!(!gs.matches("OBLATE_SPHEROID"));
        assert!(!gs.matches("oblate_Spheroid"));
    }

    #[test]
    fn test_serialization_roundtrip() {
        let original = GoldStandard::new(
            [42u8; 32],
            "Semaglutide".to_string(),
            "treats_condition".to_string(),
            "type_2_diabetes".to_string(),
            123456,
            "admin_bob".to_string(),
        );

        let serialized = serde::serialize(&original).expect("serialize");
        let deserialized: GoldStandard = serde::deserialize(&serialized).expect("deserialize");

        assert_eq!(original, deserialized);
    }
}
