//! TrustGraphStore data models for EigenTrust computation.
//!
//! This module defines the core data structures for the trust graph:
//! - `TrustEdge`: A directed trust relationship between agents
//! - `EigenTrustState`: The computed global trust scores
//! - `EigenTrustConfig`: Configuration for power iteration

/// Default alpha (damping factor) for EigenTrust.
/// 0.1 means 90% of trust flows through the graph, 10% from seeds.
pub const DEFAULT_ALPHA: f32 = 0.1;

/// Default maximum iterations for power iteration convergence.
/// Higher value ensures convergence even with oscillating graphs.
pub const DEFAULT_MAX_ITERATIONS: u32 = 100;

/// Default convergence threshold (epsilon).
/// Slightly relaxed to handle graphs with dangling nodes that oscillate.
pub const DEFAULT_EPSILON: f32 = 1e-4;

/// A directed trust edge from one agent to another.
///
/// # Invariants
///
/// - `weight` is in range [0.0, 1.0]
/// - `from_agent` and `to_agent` are Ed25519 public keys
/// - An agent cannot trust themselves (from_agent != to_agent)
#[derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Clone, PartialEq)]
#[archive(check_bytes)]
pub struct TrustEdge {
    /// Agent granting trust (Ed25519 public key).
    pub from_agent: [u8; 32],
    /// Agent receiving trust (Ed25519 public key).
    pub to_agent: [u8; 32],
    /// Trust weight (0.0 = no trust, 1.0 = full trust).
    pub weight: f32,
    /// Unix timestamp when this edge was created.
    pub created_at: u64,
    /// Optional human-readable reason for the trust relationship.
    pub reason: Option<String>,
}

impl TrustEdge {
    /// Create a new trust edge.
    ///
    /// # Arguments
    /// * `from_agent` - Agent granting trust
    /// * `to_agent` - Agent receiving trust
    /// * `weight` - Trust weight (clamped to [0.0, 1.0])
    /// * `created_at` - Unix timestamp
    /// * `reason` - Optional reason for trust
    pub fn new(
        from_agent: [u8; 32],
        to_agent: [u8; 32],
        weight: f32,
        created_at: u64,
        reason: Option<String>,
    ) -> Self {
        Self { from_agent, to_agent, weight: weight.clamp(0.0, 1.0), created_at, reason }
    }

    /// Check if this edge represents valid trust (non-zero weight, different agents).
    pub fn is_valid(&self) -> bool {
        self.weight > 0.0 && self.from_agent != self.to_agent
    }
}

/// Configuration for EigenTrust power iteration.
///
/// # Parameters
///
/// - `alpha`: Damping factor. Controls how much trust flows from seeds vs. graph.
///   - α = 0.0: All trust from graph (vulnerable to Sybil attacks)
///   - α = 1.0: All trust from seeds (no graph propagation)
///   - α = 0.1 (default): 90% graph, 10% seeds (balanced)
///
/// - `max_iterations`: Safety limit for convergence.
///   - Most graphs converge in 10-15 iterations
///   - Default 20 provides safety margin
///
/// - `epsilon`: Convergence threshold (L1 norm of change).
///   - 1e-6 is sufficient for most applications
#[derive(Debug, Clone, Copy)]
pub struct EigenTrustConfig {
    /// Damping factor: probability of jumping to a seed (default 0.1).
    pub alpha: f32,
    /// Maximum iterations before stopping (default 20).
    pub max_iterations: u32,
    /// Convergence threshold (default 1e-6).
    pub epsilon: f32,
}

impl Default for EigenTrustConfig {
    fn default() -> Self {
        Self {
            alpha: DEFAULT_ALPHA,
            max_iterations: DEFAULT_MAX_ITERATIONS,
            epsilon: DEFAULT_EPSILON,
        }
    }
}

impl EigenTrustConfig {
    /// Create a new config with custom parameters.
    pub fn new(alpha: f32, max_iterations: u32, epsilon: f32) -> Self {
        Self { alpha: alpha.clamp(0.0, 1.0), max_iterations, epsilon }
    }
}

/// An agent-score pair for EigenTrust state serialization.
#[derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Clone, PartialEq)]
#[archive(check_bytes)]
pub struct AgentScore {
    /// Agent's Ed25519 public key.
    pub agent: [u8; 32],
    /// Global trust score (normalized to sum to 1.0 across all agents).
    pub score: f32,
}

impl AgentScore {
    /// Create a new agent-score pair.
    pub fn new(agent: [u8; 32], score: f32) -> Self {
        Self { agent, score }
    }
}

/// The computed EigenTrust state after power iteration.
///
/// This represents a snapshot of global trust scores for all agents
/// in the trust graph at a specific point in time.
#[derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Clone)]
#[archive(check_bytes)]
pub struct EigenTrustState {
    /// Agent ID → global trust score pairs.
    /// Scores are normalized to sum to 1.0.
    pub scores: Vec<AgentScore>,
    /// Unix timestamp when this state was computed.
    pub computed_at: u64,
    /// Number of iterations to converge.
    pub iterations: u32,
    /// Final L1 norm of change (convergence delta).
    pub convergence_delta: f32,
}

impl EigenTrustState {
    /// Create an empty state (no agents).
    pub fn empty(timestamp: u64) -> Self {
        Self { scores: Vec::new(), computed_at: timestamp, iterations: 0, convergence_delta: 0.0 }
    }

    /// Get the trust score for a specific agent.
    ///
    /// Returns 0.0 if the agent is not in the graph.
    pub fn get_score(&self, agent: &[u8; 32]) -> f32 {
        self.scores.iter().find(|s| &s.agent == agent).map(|s| s.score).unwrap_or(0.0)
    }

    /// Check if the computation converged.
    pub fn converged(&self, config: &EigenTrustConfig) -> bool {
        self.convergence_delta < config.epsilon
    }
}

/// Result of EigenTrust computation.
#[derive(Debug)]
pub struct EigenTrustResult {
    /// The computed state.
    pub state: EigenTrustState,
    /// Whether the algorithm converged within max_iterations.
    pub converged: bool,
}

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

    #[test]
    fn test_trust_edge_new_clamps_weight() {
        let edge = TrustEdge::new([1u8; 32], [2u8; 32], 1.5, 1000, None);
        assert!((edge.weight - 1.0).abs() < f32::EPSILON);

        let edge = TrustEdge::new([1u8; 32], [2u8; 32], -0.5, 1000, None);
        assert!((edge.weight - 0.0).abs() < f32::EPSILON);
    }

    #[test]
    fn test_trust_edge_is_valid() {
        // Valid edge
        let edge = TrustEdge::new([1u8; 32], [2u8; 32], 0.8, 1000, None);
        assert!(edge.is_valid());

        // Zero weight = invalid
        let edge = TrustEdge::new([1u8; 32], [2u8; 32], 0.0, 1000, None);
        assert!(!edge.is_valid());

        // Self-trust = invalid
        let edge = TrustEdge::new([1u8; 32], [1u8; 32], 0.8, 1000, None);
        assert!(!edge.is_valid());
    }

    #[test]
    fn test_eigentrust_config_default() {
        let config = EigenTrustConfig::default();
        assert!((config.alpha - 0.1).abs() < f32::EPSILON);
        assert_eq!(config.max_iterations, 100);
        assert!((config.epsilon - 1e-4).abs() < f32::EPSILON);
    }

    #[test]
    fn test_eigentrust_state_get_score() {
        let state = EigenTrustState {
            scores: vec![
                AgentScore::new([1u8; 32], 0.5),
                AgentScore::new([2u8; 32], 0.3),
                AgentScore::new([3u8; 32], 0.2),
            ],
            computed_at: 1000,
            iterations: 10,
            convergence_delta: 1e-8,
        };

        assert!((state.get_score(&[1u8; 32]) - 0.5).abs() < f32::EPSILON);
        assert!((state.get_score(&[2u8; 32]) - 0.3).abs() < f32::EPSILON);
        assert!((state.get_score(&[99u8; 32]) - 0.0).abs() < f32::EPSILON); // Missing agent
    }

    #[test]
    fn test_eigentrust_state_converged() {
        let config = EigenTrustConfig::default();

        let converged_state = EigenTrustState {
            scores: vec![],
            computed_at: 1000,
            iterations: 10,
            convergence_delta: 1e-8,
        };
        assert!(converged_state.converged(&config));

        let not_converged_state = EigenTrustState {
            scores: vec![],
            computed_at: 1000,
            iterations: 20,
            convergence_delta: 1e-4,
        };
        assert!(!not_converged_state.converged(&config));
    }
}
