//! Core types for simulation results, errors, and configuration.

use thiserror::Error;

pub use crate::strategy::{AgentSpec, StrategyMetrics};

/// The outcome of a simulation run.
///
/// This struct captures both success metrics and any errors encountered,
/// allowing callers to programmatically verify simulation outcomes.
#[derive(Debug, Clone)]
pub struct SimulationResult {
    /// Number of assertions successfully written to WAL.
    pub assertions_written: u64,

    /// Number of assertions successfully verified from KV store.
    pub assertions_verified: u64,

    /// Number of queries executed via QueryEngine.
    pub queries_executed: u64,

    /// Number of votes written to WAL.
    pub votes_written: u64,

    /// Whether the recency lens test passed.
    pub recency_test_passed: bool,

    /// Whether the lifecycle filtering test passed.
    pub lifecycle_test_passed: bool,

    /// Whether the query audit verification passed.
    pub audit_test_passed: bool,

    /// Whether the vote-aware consensus test passed (Arena 2.2).
    pub vote_consensus_test_passed: bool,

    /// Whether the troll resistance test passed (Arena 2.3).
    pub troll_resistance_test_passed: bool,

    /// Whether the materialized view test passed (Arena 3.1).
    pub mv_integration_test_passed: bool,

    /// Whether fast-path verification passed (Arena 3.2).
    pub fast_path_test_passed: bool,

    /// Whether MV freshness test passed (Arena 3.3).
    pub mv_freshness_test_passed: bool,

    /// Whether persona differentiation test passed (Arena 4).
    pub persona_test_passed: bool,

    /// Per-strategy activity metrics (Arena 4).
    pub strategy_metrics: Vec<(String, StrategyMetrics)>,

    /// Number of materialized views created.
    pub views_materialized: u64,

    /// Errors encountered during the simulation (non-fatal).
    /// An empty vector indicates complete success.
    pub errors: Vec<SimulationError>,

    /// Number of agents that participated.
    pub agent_count: usize,

    /// Number of ticks executed.
    pub tick_count: usize,
}

impl SimulationResult {
    /// Returns true if the simulation completed without errors.
    ///
    /// Note: We don't check assertions_written == assertions_verified because
    /// Arena 2 tests write additional test assertions that are verified through
    /// the VoteAwareConsensusLens rather than the main verification loop.
    pub fn is_success(&self) -> bool {
        self.errors.is_empty()
            && self.recency_test_passed
            && self.lifecycle_test_passed
            && self.audit_test_passed
            && self.vote_consensus_test_passed
            && self.troll_resistance_test_passed
            && self.mv_integration_test_passed
            && self.fast_path_test_passed
            && self.mv_freshness_test_passed
            && self.persona_test_passed
    }

    /// Returns a human-readable summary of the simulation.
    pub fn summary(&self) -> String {
        if self.is_success() {
            format!(
                "✅ Success: {} assertions, {} votes, {} queries, {} MVs | \
                 recency={}, lifecycle={}, audit={}, vote_consensus={}, troll_resist={}, \
                 mv_integ={}, fast_path={}, mv_fresh={}, persona={}",
                self.assertions_written,
                self.votes_written,
                self.queries_executed,
                self.views_materialized,
                if self.recency_test_passed { "✓" } else { "✗" },
                if self.lifecycle_test_passed { "✓" } else { "✗" },
                if self.audit_test_passed { "✓" } else { "✗" },
                if self.vote_consensus_test_passed { "✓" } else { "✗" },
                if self.troll_resistance_test_passed { "✓" } else { "✗" },
                if self.mv_integration_test_passed { "✓" } else { "✗" },
                if self.fast_path_test_passed { "✓" } else { "✗" },
                if self.mv_freshness_test_passed { "✓" } else { "✗" },
                if self.persona_test_passed { "✓" } else { "✗" },
            )
        } else {
            format!(
                "❌ Failed: {} assertions, {} votes, {} errors, {} MVs | \
                 recency={}, lifecycle={}, audit={}, vote_consensus={}, troll_resist={}, \
                 mv_integ={}, fast_path={}, mv_fresh={}, persona={}",
                self.assertions_written,
                self.votes_written,
                self.errors.len(),
                self.views_materialized,
                if self.recency_test_passed { "✓" } else { "✗" },
                if self.lifecycle_test_passed { "✓" } else { "✗" },
                if self.audit_test_passed { "✓" } else { "✗" },
                if self.vote_consensus_test_passed { "✓" } else { "✗" },
                if self.troll_resistance_test_passed { "✓" } else { "✗" },
                if self.mv_integration_test_passed { "✓" } else { "✗" },
                if self.fast_path_test_passed { "✓" } else { "✗" },
                if self.mv_freshness_test_passed { "✓" } else { "✗" },
                if self.persona_test_passed { "✓" } else { "✗" },
            )
        }
    }
}

/// A non-fatal error encountered during simulation.
#[derive(Debug, Clone)]
pub struct SimulationError {
    /// Which tick the error occurred on (0-indexed), or 0 for scenario errors.
    pub tick: u64,

    /// The category of error.
    pub kind: ErrorKind,

    /// Human-readable error description.
    pub message: String,
}

/// Categories of simulation errors.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorKind {
    /// Failed to write assertion to WAL.
    WriteFailure,

    /// Assertion not found in KV store after ingestion.
    VerificationFailure,

    /// Ed25519 signature verification failed.
    SignatureInvalid,

    /// Deserialization of stored data failed.
    StorageCorruption,

    /// Serialization of assertion failed.
    SerializationFailure,

    /// Query execution failed.
    QueryFailure,

    /// Lens resolution produced unexpected result.
    LensResolutionFailure,

    /// Audit trail verification failed.
    AuditFailure,

    /// Failed to write vote to WAL.
    VoteWriteFailure,

    /// Vote-aware consensus resolution failed.
    VoteConsensusFailure,

    /// Materializer operation failed.
    MaterializerFailure,
}

/// Configuration for a simulation run.
#[derive(Debug, Clone)]
pub struct SimulationConfig {
    /// Agent specifications: how many of each strategy type.
    pub agents: Vec<AgentSpec>,

    /// Number of ticks (assertion cycles) to run.
    pub tick_count: usize,

    /// Milliseconds to wait for ingestion to complete.
    pub ingestion_wait_ms: u64,
}

impl SimulationConfig {
    /// Total number of agents across all specs.
    pub fn agent_count(&self) -> usize {
        self.agents.iter().map(|s| s.count).sum()
    }
}

impl Default for SimulationConfig {
    fn default() -> Self {
        use crate::strategy::StrategyType;

        Self {
            agents: vec![
                AgentSpec { count: 1, strategy: StrategyType::Scientist },
                AgentSpec { count: 1, strategy: StrategyType::Troll },
                AgentSpec { count: 1, strategy: StrategyType::Believer },
            ],
            tick_count: 10,
            ingestion_wait_ms: 500,
        }
    }
}

/// Fatal errors that prevent the simulation from running.
#[derive(Error, Debug)]
pub enum SimulationSetupError {
    /// Failed to create temporary directory for WAL.
    #[error("Failed to create WAL directory: {0}")]
    WalDirectory(String),

    /// Failed to create temporary directory for KV store.
    #[error("Failed to create store directory: {0}")]
    StoreDirectory(String),

    /// Failed to open the WAL journal.
    #[error("Failed to open journal: {0}")]
    JournalOpen(String),

    /// Failed to open the KV store.
    #[error("Failed to open store: {0}")]
    StoreOpen(String),

    /// Failed to create the ingestor.
    #[error("Failed to create ingestor: {0}")]
    IngestorCreate(String),
}
