//! Smoke tests for the StemeDB simulation.
//!
//! These tests validate that the simulation infrastructure works correctly
//! and can be run in CI. They exercise the core simulation loop and verify
//! that the Spine (WAL + Ingestor + KV Store), Cortex (Query + Lenses),
//! and Ballot Box (Votes + VoteAwareConsensusLens) correctly process data.

use stemedb_sim::{
    run_simulation, AgentSpec, ErrorKind, SimulationConfig, SimulationResult, StrategyType,
};

/// Verify the default simulation configuration succeeds.
///
/// This is the primary smoke test - if this passes, Spine, Cortex, and Ballot Box are working.
#[tokio::test]
async fn smoke_default_simulation_succeeds() {
    let config = SimulationConfig::default();
    let result = run_simulation(config).await.expect("Simulation setup should not fail");

    assert!(result.is_success(), "Default simulation should succeed. Errors: {:?}", result.errors);
    // All Arena 1 tests should pass
    assert!(result.recency_test_passed, "Recency lens test should pass");
    assert!(result.lifecycle_test_passed, "Lifecycle filtering test should pass");
    assert!(result.audit_test_passed, "Query audit test should pass");
    // All Arena 2 tests should pass
    assert!(result.vote_consensus_test_passed, "Vote consensus test should pass");
    assert!(result.troll_resistance_test_passed, "Troll resistance test should pass");
    assert!(result.votes_written >= 6, "Should have written at least 6 votes");
    // All Arena 3 tests should pass
    assert!(result.mv_integration_test_passed, "MV integration test should pass");
    assert!(result.fast_path_test_passed, "Fast-path test should pass");
    assert!(result.mv_freshness_test_passed, "MV freshness test should pass");
    assert!(result.views_materialized >= 1, "Should have materialized at least 1 view");
}

/// Verify simulation works with increased load.
#[tokio::test]
async fn smoke_high_volume_simulation() {
    let config = SimulationConfig {
        agents: vec![
            AgentSpec { count: 4, strategy: StrategyType::Scientist },
            AgentSpec { count: 3, strategy: StrategyType::Troll },
            AgentSpec { count: 3, strategy: StrategyType::Believer },
        ],
        tick_count: 50,
        ingestion_wait_ms: 1000, // More time for larger workload
    };

    let result = run_simulation(config).await.expect("Simulation setup should not fail");

    assert!(
        result.is_success(),
        "High-volume simulation should succeed. Errors: {:?}",
        result.errors
    );
    // Strategy-driven: agents may assert, vote, query, or skip per tick
    assert!(result.assertions_written >= 16, "Should have arena test assertions + base");
    // All Arena 1 + 2 + 3 tests should pass
    assert!(result.recency_test_passed);
    assert!(result.lifecycle_test_passed);
    assert!(result.audit_test_passed);
    assert!(result.vote_consensus_test_passed);
    assert!(result.troll_resistance_test_passed);
    assert!(result.mv_integration_test_passed);
    assert!(result.fast_path_test_passed);
    assert!(result.mv_freshness_test_passed);
}

/// Verify simulation result accessors work correctly.
#[test]
fn test_simulation_result_is_success() {
    // Success case: all assertions verified, no errors, all tests pass
    let success = SimulationResult {
        assertions_written: 10,
        assertions_verified: 10,
        queries_executed: 12,
        votes_written: 6,
        recency_test_passed: true,
        lifecycle_test_passed: true,
        audit_test_passed: true,
        vote_consensus_test_passed: true,
        troll_resistance_test_passed: true,
        mv_integration_test_passed: true,
        fast_path_test_passed: true,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 3,
        errors: vec![],
        agent_count: 3,
        tick_count: 10,
    };
    assert!(success.is_success());

    // Note: mismatched assertions_written != assertions_verified is allowed
    // because Arena 2 tests write additional test assertions.
    let with_mismatch = SimulationResult {
        assertions_written: 10,
        assertions_verified: 8,
        queries_executed: 10,
        votes_written: 6,
        recency_test_passed: true,
        lifecycle_test_passed: true,
        audit_test_passed: true,
        vote_consensus_test_passed: true,
        troll_resistance_test_passed: true,
        mv_integration_test_passed: true,
        fast_path_test_passed: true,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 3,
        errors: vec![],
        agent_count: 3,
        tick_count: 10,
    };
    // This is now allowed - mismatched counts don't fail
    assert!(with_mismatch.is_success());

    // Failure case: has errors
    let with_errors = SimulationResult {
        assertions_written: 10,
        assertions_verified: 10,
        queries_executed: 12,
        votes_written: 6,
        recency_test_passed: true,
        lifecycle_test_passed: true,
        audit_test_passed: true,
        vote_consensus_test_passed: true,
        troll_resistance_test_passed: true,
        mv_integration_test_passed: true,
        fast_path_test_passed: true,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 3,
        errors: vec![stemedb_sim::SimulationError {
            tick: 5,
            kind: ErrorKind::VerificationFailure,
            message: "Test error".to_string(),
        }],
        agent_count: 3,
        tick_count: 10,
    };
    assert!(!with_errors.is_success());

    // Failure case: recency test failed
    let recency_failed = SimulationResult {
        assertions_written: 10,
        assertions_verified: 10,
        queries_executed: 12,
        votes_written: 6,
        recency_test_passed: false,
        lifecycle_test_passed: true,
        audit_test_passed: true,
        vote_consensus_test_passed: true,
        troll_resistance_test_passed: true,
        mv_integration_test_passed: true,
        fast_path_test_passed: true,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 3,
        errors: vec![],
        agent_count: 3,
        tick_count: 10,
    };
    assert!(!recency_failed.is_success());

    // Failure case: lifecycle test failed
    let lifecycle_failed = SimulationResult {
        assertions_written: 10,
        assertions_verified: 10,
        queries_executed: 12,
        votes_written: 6,
        recency_test_passed: true,
        lifecycle_test_passed: false,
        audit_test_passed: true,
        vote_consensus_test_passed: true,
        troll_resistance_test_passed: true,
        mv_integration_test_passed: true,
        fast_path_test_passed: true,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 3,
        errors: vec![],
        agent_count: 3,
        tick_count: 10,
    };
    assert!(!lifecycle_failed.is_success());

    // Failure case: audit test failed
    let audit_failed = SimulationResult {
        assertions_written: 10,
        assertions_verified: 10,
        queries_executed: 12,
        votes_written: 6,
        recency_test_passed: true,
        lifecycle_test_passed: true,
        audit_test_passed: false,
        vote_consensus_test_passed: true,
        troll_resistance_test_passed: true,
        mv_integration_test_passed: true,
        fast_path_test_passed: true,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 3,
        errors: vec![],
        agent_count: 3,
        tick_count: 10,
    };
    assert!(!audit_failed.is_success());

    // Failure case: vote consensus test failed
    let vote_consensus_failed = SimulationResult {
        assertions_written: 10,
        assertions_verified: 10,
        queries_executed: 12,
        votes_written: 6,
        recency_test_passed: true,
        lifecycle_test_passed: true,
        audit_test_passed: true,
        vote_consensus_test_passed: false,
        troll_resistance_test_passed: true,
        mv_integration_test_passed: true,
        fast_path_test_passed: true,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 3,
        errors: vec![],
        agent_count: 3,
        tick_count: 10,
    };
    assert!(!vote_consensus_failed.is_success());

    // Failure case: troll resistance test failed
    let troll_resistance_failed = SimulationResult {
        assertions_written: 10,
        assertions_verified: 10,
        queries_executed: 12,
        votes_written: 6,
        recency_test_passed: true,
        lifecycle_test_passed: true,
        audit_test_passed: true,
        vote_consensus_test_passed: true,
        troll_resistance_test_passed: false,
        mv_integration_test_passed: true,
        fast_path_test_passed: true,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 3,
        errors: vec![],
        agent_count: 3,
        tick_count: 10,
    };
    assert!(!troll_resistance_failed.is_success());
}

/// Verify summary formatting.
#[test]
fn test_simulation_result_summary_format() {
    let success = SimulationResult {
        assertions_written: 10,
        assertions_verified: 10,
        queries_executed: 12,
        votes_written: 6,
        recency_test_passed: true,
        lifecycle_test_passed: true,
        audit_test_passed: true,
        vote_consensus_test_passed: true,
        troll_resistance_test_passed: true,
        mv_integration_test_passed: true,
        fast_path_test_passed: true,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 3,
        errors: vec![],
        agent_count: 3,
        tick_count: 10,
    };
    let summary = success.summary();
    assert!(summary.contains("✅"), "Success should show checkmark");
    assert!(summary.contains("10"), "Should show assertion count");
    assert!(summary.contains("6"), "Should show vote count");
    assert!(summary.contains("recency=✓"), "Should show recency passed");
    assert!(summary.contains("lifecycle=✓"), "Should show lifecycle passed");
    assert!(summary.contains("audit=✓"), "Should show audit passed");
    assert!(summary.contains("vote_consensus=✓"), "Should show vote consensus passed");
    assert!(summary.contains("troll_resist=✓"), "Should show troll resistance passed");
    assert!(summary.contains("mv_integ=✓"), "Should show MV integration passed");
    assert!(summary.contains("fast_path=✓"), "Should show fast-path passed");
    assert!(summary.contains("mv_fresh=✓"), "Should show MV freshness passed");

    let failure = SimulationResult {
        assertions_written: 10,
        assertions_verified: 8,
        queries_executed: 10,
        votes_written: 6,
        recency_test_passed: false,
        lifecycle_test_passed: true,
        audit_test_passed: true,
        vote_consensus_test_passed: true,
        troll_resistance_test_passed: false,
        mv_integration_test_passed: true,
        fast_path_test_passed: false,
        mv_freshness_test_passed: true,
        persona_test_passed: true,
        strategy_metrics: vec![],
        views_materialized: 2,
        errors: vec![stemedb_sim::SimulationError {
            tick: 5,
            kind: ErrorKind::VerificationFailure,
            message: "Test".to_string(),
        }],
        agent_count: 3,
        tick_count: 10,
    };
    let summary = failure.summary();
    assert!(summary.contains("❌"), "Failure should show X");
    assert!(summary.contains("1 error"), "Should show error count");
    assert!(summary.contains("recency=✗"), "Should show recency failed");
    assert!(summary.contains("troll_resist=✗"), "Should show troll resistance failed");
    assert!(summary.contains("fast_path=✗"), "Should show fast-path failed");
}

/// Verify all error kinds are representable.
#[test]
fn test_error_kinds_are_complete() {
    // This test documents all error kinds - if a new one is added,
    // this test should be updated to cover it.
    let kinds = [
        ErrorKind::WriteFailure,
        ErrorKind::VerificationFailure,
        ErrorKind::SignatureInvalid,
        ErrorKind::StorageCorruption,
        ErrorKind::SerializationFailure,
        ErrorKind::QueryFailure,
        ErrorKind::LensResolutionFailure,
        ErrorKind::AuditFailure,
        ErrorKind::VoteWriteFailure,
        ErrorKind::VoteConsensusFailure,
        ErrorKind::MaterializerFailure,
    ];

    for kind in kinds {
        let error =
            stemedb_sim::SimulationError { tick: 0, kind, message: format!("{:?} test", kind) };
        // Verify Debug trait works
        let debug_str = format!("{:?}", error);
        assert!(!debug_str.is_empty());
    }
}

/// Verify minimum viable configuration works.
/// Note: Minimal simulation requires at least 3 agents for voting tests.
#[tokio::test]
async fn smoke_minimal_simulation() {
    let config = SimulationConfig {
        agents: vec![
            AgentSpec { count: 1, strategy: StrategyType::Scientist },
            AgentSpec { count: 1, strategy: StrategyType::Troll },
            AgentSpec { count: 1, strategy: StrategyType::Believer },
        ],
        tick_count: 1,
        ingestion_wait_ms: 300,
    };

    let result = run_simulation(config).await.expect("Simulation setup should not fail");

    assert!(result.is_success(), "Minimal simulation should succeed: {:?}", result.errors);
    // Strategy-driven: agents may assert, vote, query, or skip per tick
    assert!(result.assertions_written >= 14, "Should have arena test assertions + base");
    assert_eq!(result.agent_count, 3);
    assert_eq!(result.tick_count, 1);
    // All Arena 1 + 2 + 3 tests should pass
    assert!(result.recency_test_passed);
    assert!(result.lifecycle_test_passed);
    assert!(result.audit_test_passed);
    assert!(result.vote_consensus_test_passed);
    assert!(result.troll_resistance_test_passed);
    assert!(result.mv_integration_test_passed);
    assert!(result.fast_path_test_passed);
    assert!(result.mv_freshness_test_passed);
}
