//! Tests for TrustGraphStore implementation.

use super::model::{EigenTrustConfig, TrustEdge};
use super::store_impl::GenericTrustGraphStore;
use super::TrustGraphStore;
use crate::HybridStore;
use std::sync::Arc;

fn agent(id: u8) -> [u8; 32] {
    let mut arr = [0u8; 32];
    arr[0] = id;
    arr
}

#[tokio::test]
async fn test_add_and_get_trust_edge() {
    let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
    let trust_store = GenericTrustGraphStore::new(store);

    let edge = TrustEdge::new(agent(1), agent(2), 0.8, 1000, Some("Test".to_string()));
    trust_store.add_trust_edge(&edge).await.expect("add");

    let retrieved = trust_store.get_trust_edge(&agent(1), &agent(2)).await.expect("get");
    assert!(retrieved.is_some());

    let retrieved_edge = retrieved.expect("edge");
    assert_eq!(retrieved_edge.from_agent, agent(1));
    assert_eq!(retrieved_edge.to_agent, agent(2));
    assert!((retrieved_edge.weight - 0.8).abs() < f32::EPSILON);
}

#[tokio::test]
async fn test_remove_trust_edge() {
    let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
    let trust_store = GenericTrustGraphStore::new(store);

    let edge = TrustEdge::new(agent(1), agent(2), 0.8, 1000, None);
    trust_store.add_trust_edge(&edge).await.expect("add");

    // Remove should return true
    let removed = trust_store.remove_trust_edge(&agent(1), &agent(2)).await.expect("remove");
    assert!(removed);

    // Edge should be gone
    let retrieved = trust_store.get_trust_edge(&agent(1), &agent(2)).await.expect("get");
    assert!(retrieved.is_none());

    // Remove again should return false
    let removed_again = trust_store.remove_trust_edge(&agent(1), &agent(2)).await.expect("remove");
    assert!(!removed_again);
}

#[tokio::test]
async fn test_get_trusts_outgoing() {
    let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
    let trust_store = GenericTrustGraphStore::new(store);

    // Agent 1 trusts agents 2, 3, 4
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(1), agent(2), 0.8, 1000, None))
        .await
        .expect("add");
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(1), agent(3), 0.6, 1000, None))
        .await
        .expect("add");
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(1), agent(4), 0.4, 1000, None))
        .await
        .expect("add");

    let trusts = trust_store.get_trusts(&agent(1)).await.expect("get");
    assert_eq!(trusts.len(), 3);

    // Verify weights
    let weight_2 = trusts.iter().find(|(a, _)| *a == agent(2)).map(|(_, w)| *w);
    let weight_3 = trusts.iter().find(|(a, _)| *a == agent(3)).map(|(_, w)| *w);
    let weight_4 = trusts.iter().find(|(a, _)| *a == agent(4)).map(|(_, w)| *w);

    assert!((weight_2.expect("weight") - 0.8).abs() < f32::EPSILON);
    assert!((weight_3.expect("weight") - 0.6).abs() < f32::EPSILON);
    assert!((weight_4.expect("weight") - 0.4).abs() < f32::EPSILON);
}

#[tokio::test]
async fn test_get_trusted_by_incoming() {
    let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
    let trust_store = GenericTrustGraphStore::new(store);

    // Agents 1, 2, 3 all trust agent 4
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(1), agent(4), 0.8, 1000, None))
        .await
        .expect("add");
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(2), agent(4), 0.6, 1000, None))
        .await
        .expect("add");
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(3), agent(4), 0.4, 1000, None))
        .await
        .expect("add");

    let trusted_by = trust_store.get_trusted_by(&agent(4)).await.expect("get");
    assert_eq!(trusted_by.len(), 3);
}

#[tokio::test]
async fn test_seed_trust_crud() {
    let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
    let trust_store = GenericTrustGraphStore::new(store);

    // Set seed trust
    trust_store.set_seed_trust(&agent(1), 1.0).await.expect("set");
    trust_store.set_seed_trust(&agent(2), 0.5).await.expect("set");

    // Get individual
    let trust1 = trust_store.get_seed_trust(&agent(1)).await.expect("get");
    let trust2 = trust_store.get_seed_trust(&agent(2)).await.expect("get");
    let trust3 = trust_store.get_seed_trust(&agent(3)).await.expect("get");

    assert!((trust1 - 1.0).abs() < f32::EPSILON);
    assert!((trust2 - 0.5).abs() < f32::EPSILON);
    assert!((trust3 - 0.0).abs() < f32::EPSILON); // Not set

    // Get all
    let all_seeds = trust_store.get_all_seed_trust().await.expect("get all");
    assert_eq!(all_seeds.len(), 2);

    // Remove
    let removed = trust_store.remove_seed_trust(&agent(1)).await.expect("remove");
    assert!(removed);

    let all_seeds = trust_store.get_all_seed_trust().await.expect("get all");
    assert_eq!(all_seeds.len(), 1);
}

#[tokio::test]
async fn test_compute_and_get_eigentrust() {
    let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
    let trust_store = GenericTrustGraphStore::new(store);

    // Set up: seed trusts agent 2, agent 2 trusts agent 3
    trust_store.set_seed_trust(&agent(1), 1.0).await.expect("set");
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(1), agent(2), 1.0, 1000, None))
        .await
        .expect("add");
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(2), agent(3), 1.0, 1000, None))
        .await
        .expect("add");

    // Compute EigenTrust
    let state =
        trust_store.compute_eigentrust(&EigenTrustConfig::default()).await.expect("compute");

    assert!(state.scores.len() >= 3);
    assert!(state.iterations > 0);

    // Get state
    let retrieved = trust_store.get_eigentrust_state().await.expect("get");
    assert!(retrieved.is_some());

    // Get individual score
    let score = trust_store.get_eigentrust_score(&agent(1)).await.expect("get");
    assert!(score > 0.0);
}

#[tokio::test]
async fn test_eigentrust_score_without_computation() {
    let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
    let trust_store = GenericTrustGraphStore::new(store);

    // Without computing, should return 0.0
    let score = trust_store.get_eigentrust_score(&agent(1)).await.expect("get");
    assert!((score - 0.0).abs() < f32::EPSILON);
}

#[tokio::test]
async fn test_sybil_resistance_isolated_ring() {
    let store = Arc::new(HybridStore::open_temp().expect("Failed to create store"));
    let trust_store = GenericTrustGraphStore::new(store);

    // Seed with no edges
    trust_store.set_seed_trust(&agent(0), 1.0).await.expect("set");

    // Isolated ring: 1 → 2 → 3 → 1 (not connected to seed)
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(1), agent(2), 1.0, 1000, None))
        .await
        .expect("add");
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(2), agent(3), 1.0, 1000, None))
        .await
        .expect("add");
    trust_store
        .add_trust_edge(&TrustEdge::new(agent(3), agent(1), 1.0, 1000, None))
        .await
        .expect("add");

    let state =
        trust_store.compute_eigentrust(&EigenTrustConfig::default()).await.expect("compute");

    // Seed should have high trust
    let seed_score = state.get_score(&agent(0));
    assert!(seed_score > 0.9, "Seed should have high trust: {}", seed_score);

    // Isolated ring should have near-zero trust
    let ring1_score = state.get_score(&agent(1));
    let ring2_score = state.get_score(&agent(2));
    let ring3_score = state.get_score(&agent(3));

    assert!(ring1_score < 0.05, "Isolated agent 1 should have low trust: {}", ring1_score);
    assert!(ring2_score < 0.05, "Isolated agent 2 should have low trust: {}", ring2_score);
    assert!(ring3_score < 0.05, "Isolated agent 3 should have low trust: {}", ring3_score);
}
