//! Tests for gold standard verification and advanced TrustRank features.

use super::*;
use crate::HybridStore;
use std::sync::Arc;
use stemedb_core::types::GoldStandard;

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

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

    // Use 60-day half-life instead of 30
    let sixty_day_half_life = 60 * 24 * 60 * 60;
    let thirty_days = 30 * 24 * 60 * 60;

    let decayed_count = trust_store
        .decay_trust_ranks(1000 + thirty_days, Some(sixty_day_half_life))
        .await
        .expect("decay");

    assert_eq!(decayed_count, 1);

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

    // After 30 days with 60-day half-life, should be ~0.707 (2^(-0.5))
    assert!((trust.score - 0.707).abs() < 0.01);
}

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

    let agent_id = [7u8; 32];

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

    // Verify with correct answer
    let adjustment = trust_store
        .verify_agent_against_gold_standard(&agent_id, "oblate_spheroid", &gs, 1000)
        .await
        .expect("verify");

    assert!(adjustment.is_reward());
    assert_eq!(adjustment.delta(), 0.05);

    // Check trust was increased
    let trust = trust_store.get_trust_rank(&agent_id).await.expect("get");
    assert!((trust.score - 0.55).abs() < 0.001); // 0.5 + 0.05
    assert_eq!(trust.assertions_count, 1);
    assert_eq!(trust.accuracy_count, 1);
}

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

    let agent_id = [8u8; 32];

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

    // Verify with incorrect answer
    let adjustment = trust_store
        .verify_agent_against_gold_standard(&agent_id, "flat", &gs, 1000)
        .await
        .expect("verify");

    assert!(adjustment.is_penalty());
    assert_eq!(adjustment.delta(), -0.1);

    // Check trust was decreased
    let trust = trust_store.get_trust_rank(&agent_id).await.expect("get");
    assert!((trust.score - 0.4).abs() < 0.001); // 0.5 - 0.1
    assert_eq!(trust.assertions_count, 1);
    assert_eq!(trust.accuracy_count, 0);
}

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

    let agent_id = [9u8; 32];

    let gs1 = GoldStandard::new(
        [0u8; 32],
        "Earth".to_string(),
        "has_shape".to_string(),
        "oblate_spheroid".to_string(),
        1000,
        "admin".to_string(),
    );

    let gs2 = GoldStandard::new(
        [1u8; 32],
        "Semaglutide".to_string(),
        "treats_condition".to_string(),
        "type_2_diabetes".to_string(),
        1000,
        "admin".to_string(),
    );

    // First verification: correct
    trust_store
        .verify_agent_against_gold_standard(&agent_id, "oblate_spheroid", &gs1, 1000)
        .await
        .expect("verify");

    // Second verification: correct
    trust_store
        .verify_agent_against_gold_standard(&agent_id, "type_2_diabetes", &gs2, 2000)
        .await
        .expect("verify");

    // Check cumulative effect
    let trust = trust_store.get_trust_rank(&agent_id).await.expect("get");
    assert!((trust.score - 0.6).abs() < 0.001); // 0.5 + 0.05 + 0.05
    assert_eq!(trust.assertions_count, 2);
    assert_eq!(trust.accuracy_count, 2);
    assert_eq!(trust.accuracy_rate(), 1.0);
}

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

    let agent_id = [10u8; 32];

    // Start with high trust
    let mut trust = TrustRank::new(agent_id, 1000);
    trust.score = 0.98;
    trust_store.put_trust_rank(&trust).await.expect("put");

    let gs = GoldStandard::new(
        [0u8; 32],
        "Test".to_string(),
        "test".to_string(),
        "correct".to_string(),
        1000,
        "admin".to_string(),
    );

    // Verify with correct answer - should clamp at 1.0
    trust_store
        .verify_agent_against_gold_standard(&agent_id, "correct", &gs, 2000)
        .await
        .expect("verify");

    let trust = trust_store.get_trust_rank(&agent_id).await.expect("get");
    assert_eq!(trust.score, 1.0); // Clamped at max
}

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

    let agent_id = [11u8; 32];
    let gs = GoldStandard::new(
        [0u8; 32],
        "Earth".to_string(),
        "has_shape".to_string(),
        "oblate_spheroid".to_string(),
        1000,
        "admin".to_string(),
    );

    // First verification with correct answer
    let adjustment = trust_store
        .verify_agent_against_gold_standard(&agent_id, "oblate_spheroid", &gs, 1001)
        .await
        .expect("verification failed");

    assert!(adjustment.is_reward(), "First correct answer should be rewarded");
    assert_eq!(adjustment.delta(), 0.05);
}

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

    let agent_id = [12u8; 32];
    let gs = GoldStandard::new(
        [0u8; 32],
        "Tesla_Inc".to_string(),
        "has_revenue".to_string(),
        "96.7".to_string(),
        1000,
        "admin".to_string(),
    );

    // First verification
    let first_adjustment = trust_store
        .verify_agent_against_gold_standard(&agent_id, "96.7", &gs, 1001)
        .await
        .expect("first verification failed");
    assert!(first_adjustment.is_reward());

    // Second verification of same gold standard
    let second_adjustment = trust_store
        .verify_agent_against_gold_standard(&agent_id, "96.7", &gs, 1002)
        .await
        .expect("second verification failed");
    assert!(
        second_adjustment.is_already_verified(),
        "Second verification should return AlreadyVerified"
    );
    assert_eq!(second_adjustment.delta(), 0.0);
}

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

    let agent_id = [13u8; 32];
    let gs1 = GoldStandard::new(
        [1u8; 32],
        "Earth".to_string(),
        "has_shape".to_string(),
        "oblate_spheroid".to_string(),
        1000,
        "admin".to_string(),
    );
    let gs2 = GoldStandard::new(
        [2u8; 32],
        "Earth".to_string(),
        "has_radius".to_string(),
        "6371".to_string(),
        1000,
        "admin".to_string(),
    );

    // Verify against first gold standard
    let first = trust_store
        .verify_agent_against_gold_standard(&agent_id, "oblate_spheroid", &gs1, 1001)
        .await
        .expect("first verification failed");
    assert!(first.is_reward());

    // Verify against second gold standard (different predicate)
    let second = trust_store
        .verify_agent_against_gold_standard(&agent_id, "6371", &gs2, 1002)
        .await
        .expect("second verification failed");
    assert!(second.is_reward(), "Different gold standard should allow verification");

    // Try first gold standard again
    let third = trust_store
        .verify_agent_against_gold_standard(&agent_id, "oblate_spheroid", &gs1, 1003)
        .await
        .expect("third verification failed");
    assert!(third.is_already_verified(), "First gold standard should be marked verified");
}

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

    let agent_id = [14u8; 32];
    let gs = GoldStandard::new(
        [0u8; 32],
        "Earth".to_string(),
        "has_shape".to_string(),
        "oblate_spheroid".to_string(),
        1000,
        "admin".to_string(),
    );

    // First verification with incorrect answer
    let first = trust_store
        .verify_agent_against_gold_standard(&agent_id, "flat", &gs, 1001)
        .await
        .expect("first verification failed");
    assert!(first.is_penalty(), "Incorrect answer should be penalized");
    assert_eq!(first.delta(), -0.1);

    // Second attempt (even with correct answer now)
    let second = trust_store
        .verify_agent_against_gold_standard(&agent_id, "oblate_spheroid", &gs, 1002)
        .await
        .expect("second verification failed");
    assert!(second.is_already_verified(), "Should not allow retry even with correct answer");
}
