//! StemeDB Simulation Library
//!
//! This module provides the core simulation logic for validating the StemeDB
//! "Spine" (Durability + Schema + Ingestion) and "Cortex" (Query + Lenses)
//! under agent-driven stress tests.
//!
//! # Design Philosophy
//!
//! Following "Philosophy of Software Design" principles:
//! - **Deep Module**: Simple `run_simulation()` interface hides all complexity
//! - **Define Errors Out of Existence**: Failures are collected, not panicked
//! - **Strategic Programming**: Built for testability and extension
//!
//! # Arena Phases
//!
//! - **Arena 0**: Spine validation (WAL + Ingestor + KV Store)
//! - **Arena 1**: Query path validation (QueryEngine + Lenses + Lifecycle + Audits)
//! - **Arena 2**: Voting & Consensus (VoteStore + VoteAwareConsensusLens)
//!
//! # Example
//!
//! ```ignore
//! use stemedb_sim::{run_simulation, SimulationConfig};
//!
//! let config = SimulationConfig::default();
//! let result = run_simulation(config).await?;
//!
//! assert_eq!(result.assertions_verified, result.assertions_written);
//! assert!(result.errors.is_empty());
//! ```

// Module declarations
mod agent;
mod arenas;
mod helpers;
mod runner;
pub mod strategy;
mod types;

// Public re-exports
pub use runner::run_simulation;
pub use strategy::{
    AgentAction, AgentSpec, AgentStrategy, StrategyMetrics, StrategyType, WorldState,
};
pub use types::{
    ErrorKind, SimulationConfig, SimulationError, SimulationResult, SimulationSetupError,
};

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_simulation_default_config_succeeds() {
        let config = SimulationConfig::default();
        let result = run_simulation(config).await.expect("Simulation should not fail setup");

        assert!(result.is_success(), "Simulation should succeed: {:?}", result.errors);
        // Arena 0: tick_count assertions (strategy-dependent, some agents may skip)
        // Arena 2: 2 (vote consensus) + 2 (troll resistance)
        // Arena 3: 1 (MV integration) + 1 (fast-path) + 10 (freshness)
        assert!(result.assertions_written >= 16, "Should have arena test assertions + base");
        // Arena 2 votes: 3 (vote consensus) + 3 (troll resistance)
        assert!(result.votes_written >= 6);
        assert!(result.recency_test_passed, "Recency test should pass");
        assert!(result.lifecycle_test_passed, "Lifecycle test should pass");
        assert!(result.audit_test_passed, "Audit test 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.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");
    }

    #[tokio::test]
    async fn test_simulation_custom_config() {
        let config = SimulationConfig {
            agents: vec![
                AgentSpec { count: 2, strategy: StrategyType::Scientist },
                AgentSpec { count: 2, strategy: StrategyType::Troll },
                AgentSpec { count: 1, strategy: StrategyType::Believer },
            ],
            tick_count: 20,
            ingestion_wait_ms: 600,
        };
        let result = run_simulation(config).await.expect("Simulation should not fail setup");

        assert!(result.is_success());
        // Strategy-driven: agents may assert, vote, query, or skip per tick
        assert!(result.assertions_written >= 16, "Should have arena test assertions + base");
        assert!(result.votes_written >= 6);
        assert_eq!(result.agent_count, 5);
        assert_eq!(result.tick_count, 20);
    }

    #[tokio::test]
    async fn test_simulation_result_summary() {
        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.summary().contains("✅"));
        assert!(success.summary().contains("recency=✓"));
        assert!(success.summary().contains("lifecycle=✓"));
        assert!(success.summary().contains("audit=✓"));
        assert!(success.summary().contains("vote_consensus=✓"));
        assert!(success.summary().contains("troll_resist=✓"));
        assert!(success.summary().contains("mv_integ=✓"));
        assert!(success.summary().contains("fast_path=✓"));
        assert!(success.summary().contains("mv_fresh=✓"));

        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![SimulationError {
                tick: 5,
                kind: ErrorKind::VerificationFailure,
                message: "Test error".to_string(),
            }],
            agent_count: 3,
            tick_count: 10,
        };
        assert!(failure.summary().contains("❌"));
        assert!(failure.summary().contains("recency=✗"));
        assert!(failure.summary().contains("fast_path=✗"));
        assert!(failure.summary().contains("troll_resist=✗"));
    }
}
