//! Basic tests for TrustRank model and CRUD operations.

use super::*;
use crate::HybridStore;
use model::{DEFAULT_HALF_LIFE_SECONDS, DEFAULT_TRUST_SCORE};
use std::sync::Arc;

#[test]
fn test_trust_rank_new() {
    let agent_id = [1u8; 32];
    let trust = TrustRank::new(agent_id, 1000);

    assert_eq!(trust.agent_id, agent_id);
    assert_eq!(trust.score, DEFAULT_TRUST_SCORE);
    assert_eq!(trust.last_updated, 1000);
    assert_eq!(trust.assertions_count, 0);
    assert_eq!(trust.accuracy_count, 0);
}

#[test]
fn test_adjust_score_clamping() {
    let mut trust = TrustRank::new([1u8; 32], 1000);

    // Add positive delta
    let score = trust.adjust_score(0.3, 2000);
    assert_eq!(score, 0.8);

    // Add too much, should clamp to 1.0
    let score = trust.adjust_score(0.5, 3000);
    assert_eq!(score, 1.0);

    // Subtract too much, should clamp to 0.0
    let score = trust.adjust_score(-2.0, 4000);
    assert_eq!(score, 0.0);
}

#[test]
fn test_record_outcome() {
    let mut trust = TrustRank::new([1u8; 32], 1000);

    trust.record_outcome(true);
    assert_eq!(trust.assertions_count, 1);
    assert_eq!(trust.accuracy_count, 1);
    assert_eq!(trust.accuracy_rate(), 1.0);

    trust.record_outcome(false);
    assert_eq!(trust.assertions_count, 2);
    assert_eq!(trust.accuracy_count, 1);
    assert_eq!(trust.accuracy_rate(), 0.5);

    trust.record_outcome(true);
    assert_eq!(trust.assertions_count, 3);
    assert_eq!(trust.accuracy_count, 2);
    assert!((trust.accuracy_rate() - 0.666666).abs() < 0.001);
}

#[test]
fn test_apply_decay() {
    let mut trust = TrustRank::new([1u8; 32], 1000);
    trust.score = 1.0; // Start at max

    // 30 days later (one half-life)
    let thirty_days = 30 * 24 * 60 * 60;
    let decayed = trust.apply_decay(1000 + thirty_days, DEFAULT_HALF_LIFE_SECONDS);

    // Should be approximately 0.5
    assert!((decayed - 0.5).abs() < 0.01);

    // 60 days later (two half-lives)
    let sixty_days = 60 * 24 * 60 * 60;
    trust.score = 1.0; // Reset
    trust.last_updated = 1000;
    let decayed = trust.apply_decay(1000 + sixty_days, DEFAULT_HALF_LIFE_SECONDS);

    // Should be approximately 0.25
    assert!((decayed - 0.25).abs() < 0.01);
}

#[test]
fn test_decay_no_time_elapsed() {
    let mut trust = TrustRank::new([1u8; 32], 1000);
    trust.score = 0.8;

    let decayed = trust.apply_decay(1000, DEFAULT_HALF_LIFE_SECONDS);

    // No time elapsed, score should be unchanged
    assert_eq!(decayed, 0.8);
}

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

    let agent_id = [1u8; 32];
    let trust = trust_store.get_trust_rank(&agent_id).await.expect("get");

    assert_eq!(trust.agent_id, agent_id);
    assert_eq!(trust.score, DEFAULT_TRUST_SCORE);
}

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

    let agent_id = [2u8; 32];
    let mut trust = TrustRank::new(agent_id, 1000);
    trust.score = 0.75;

    trust_store.put_trust_rank(&trust).await.expect("put");

    let retrieved = trust_store.get_trust_rank(&agent_id).await.expect("get");

    assert_eq!(retrieved.score, 0.75);
    assert_eq!(retrieved.agent_id, agent_id);
}

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

    let agent_id = [3u8; 32];

    // First update creates default
    let score = trust_store.update_trust_rank(&agent_id, 0.2, 1000).await.expect("update");
    assert!((score - 0.7).abs() < f32::EPSILON); // 0.5 + 0.2

    // Second update modifies existing
    let score = trust_store.update_trust_rank(&agent_id, -0.3, 2000).await.expect("update");
    assert!((score - 0.4).abs() < 0.001); // 0.7 - 0.3
}

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

    let agent_id = [4u8; 32];

    // Record accurate outcome
    let score = trust_store.record_outcome(&agent_id, true, 1000).await.expect("record");
    assert!((score - 0.55).abs() < 0.001); // 0.5 + 0.05

    // Record inaccurate outcome
    let score = trust_store.record_outcome(&agent_id, false, 2000).await.expect("record");
    assert!((score - 0.45).abs() < 0.001); // 0.55 - 0.1

    // Verify accuracy tracking
    let trust = trust_store.get_trust_rank(&agent_id).await.expect("get");
    assert_eq!(trust.assertions_count, 2);
    assert_eq!(trust.accuracy_count, 1);
    assert_eq!(trust.accuracy_rate(), 0.5);
}

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

    // Create several agents with different scores
    for i in 0..5 {
        let agent_id = [i; 32];
        let mut trust = TrustRank::new(agent_id, 1000);
        trust.score = 0.8;
        trust_store.put_trust_rank(&trust).await.expect("put");
    }

    // Apply decay after 30 days (one half-life)
    let thirty_days = 30 * 24 * 60 * 60;
    let decayed_count =
        trust_store.decay_trust_ranks(1000 + thirty_days, None).await.expect("decay");

    assert_eq!(decayed_count, 5);

    // Verify all scores were decayed
    for i in 0..5 {
        let agent_id = [i; 32];
        let trust = trust_store.get_trust_rank(&agent_id).await.expect("get");
        // 0.8 * 0.5 = 0.4
        assert!((trust.score - 0.4).abs() < 0.01);
    }
}

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

    let agent_id = [5u8; 32];
    let trust = TrustRank::new(agent_id, 1000);
    trust_store.put_trust_rank(&trust).await.expect("put");

    // No time elapsed, should not update
    let decayed_count = trust_store.decay_trust_ranks(1000, None).await.expect("decay");

    assert_eq!(decayed_count, 0);
}

#[tokio::test]
async fn test_serialization_roundtrip() {
    let original = TrustRank {
        agent_id: [42u8; 32],
        score: 0.75,
        last_updated: 123456,
        assertions_count: 100,
        accuracy_count: 85,
    };

    let serialized =
        GenericTrustRankStore::<HybridStore>::serialize_trust_rank(&original).expect("serialize");
    let deserialized = GenericTrustRankStore::<HybridStore>::deserialize_trust_rank(&serialized)
        .expect("deserialize");

    assert_eq!(original, deserialized);
}
