//! Integration tests for admission control (The Shield).
//!
//! These tests verify the DTO conversion and response formatting.
//! The core admission logic is tested in stemedb-storage unit tests.

use stemedb_api::dto::{AdmissionStatusResponse, TrustTierDto};
use stemedb_core::types::{AdmissionConfig, TrustTier};
use stemedb_storage::AdmissionStatus;

#[test]
fn test_trust_tier_dto_conversion() {
    // Test all tier conversions
    assert_eq!(TrustTierDto::from(TrustTier::Untrusted), TrustTierDto::Untrusted);
    assert_eq!(TrustTierDto::from(TrustTier::Limited), TrustTierDto::Limited);
    assert_eq!(TrustTierDto::from(TrustTier::Verified), TrustTierDto::Verified);
    assert_eq!(TrustTierDto::from(TrustTier::Trusted), TrustTierDto::Trusted);
    assert_eq!(TrustTierDto::from(TrustTier::Authority), TrustTierDto::Authority);
}

#[test]
fn test_admission_status_response_new_agent() {
    let status = AdmissionStatus::new(0.5, 0, 16);
    let config = AdmissionConfig::default();

    let response = AdmissionStatusResponse::from_status("abc123".to_string(), &status, &config);

    assert_eq!(response.tier, TrustTierDto::Verified);
    assert!((response.trust_score - 0.5).abs() < f32::EPSILON);
    assert_eq!(response.assertions_count, 0);
    assert_eq!(response.pow_difficulty, 16);
    assert!(response.pow_required);
    assert_eq!(response.base_quota_limit, 10_000);
    assert_eq!(response.effective_quota_limit, 10_000);
    assert!((response.quota_multiplier - 1.0).abs() < f32::EPSILON);

    // New agent should see milestones
    assert_eq!(response.assertions_until_reduced_difficulty, Some(10));
    assert_eq!(response.assertions_until_exemption, Some(50));
}

#[test]
fn test_admission_status_response_graduated() {
    let status = AdmissionStatus::new(0.7, 100, 0);
    let config = AdmissionConfig::default();

    let response = AdmissionStatusResponse::from_status("graduated".to_string(), &status, &config);

    assert_eq!(response.tier, TrustTierDto::Trusted);
    assert!(!response.pow_required);
    assert_eq!(response.pow_difficulty, 0);
    assert_eq!(response.effective_quota_limit, 20_000);

    // Graduated agent shouldn't see milestones
    assert_eq!(response.assertions_until_reduced_difficulty, None);
    assert_eq!(response.assertions_until_exemption, None);
}

#[test]
fn test_admission_status_response_partially_graduated() {
    // Agent with 25 assertions (past initial, not yet graduated)
    let status = AdmissionStatus::new(0.4, 25, 1);
    let config = AdmissionConfig::default();

    let response = AdmissionStatusResponse::from_status("partial".to_string(), &status, &config);

    assert_eq!(response.tier, TrustTierDto::Limited);
    assert!(response.pow_required);
    assert_eq!(response.pow_difficulty, 1);

    // Past initial threshold, so no "until reduced" milestone
    assert_eq!(response.assertions_until_reduced_difficulty, None);
    // Still 25 assertions until exemption
    assert_eq!(response.assertions_until_exemption, Some(25));
}

#[test]
fn test_all_tier_quotas() {
    let config = AdmissionConfig::default();

    // Test each tier
    let test_cases = [
        (0.1, TrustTierDto::Untrusted, 1_000),
        (0.4, TrustTierDto::Limited, 5_000),
        (0.5, TrustTierDto::Verified, 10_000),
        (0.8, TrustTierDto::Trusted, 20_000),
        (0.95, TrustTierDto::Authority, 100_000),
    ];

    for (score, expected_tier, expected_quota) in test_cases {
        let status = AdmissionStatus::new(score, 100, 0);
        let response = AdmissionStatusResponse::from_status("test".to_string(), &status, &config);

        assert_eq!(response.tier, expected_tier, "Wrong tier for score {}", score);
        assert_eq!(
            response.effective_quota_limit, expected_quota,
            "Wrong quota for score {}",
            score
        );
    }
}

#[test]
fn test_pow_difficulty_graduation() {
    let config = AdmissionConfig::default();

    // First 10 assertions: 16 bits
    for count in 0..10 {
        let difficulty = config.compute_difficulty(count, 0.3);
        assert_eq!(difficulty, 16, "Wrong difficulty for {} assertions", count);
    }

    // 10-49: 1 bit
    for count in 10..50 {
        let difficulty = config.compute_difficulty(count, 0.3);
        assert_eq!(difficulty, 1, "Wrong difficulty for {} assertions", count);
    }

    // 50+: exempt
    let difficulty = config.compute_difficulty(50, 0.3);
    assert_eq!(difficulty, 0);

    // Trust exemption
    let difficulty = config.compute_difficulty(5, 0.6);
    assert_eq!(difficulty, 0, "High trust should be exempt");
}
