//! # Causal
//!
//! Event-sourcing runtime for Rust, [KurrentDB](https://www.kurrent.io/)-aligned:
//! a typed `Event → Reactor → Event` loop over an append-only event log.
//! Runs entirely in-memory for tests ([`MemoryStore`]); production backends
//! (KurrentDB event log, Postgres cursors/snapshots) live in `causal_replay`.
//!
//! The vocabulary mirrors KurrentDB's where the concepts overlap:
//! [`EventData`](types::EventData) / [`RecordedEvent`], `causation_id` /
//! `correlation_id`, [`StreamRevision`] (0-indexed), [`StreamState`] for
//! optimistic concurrency, `{category}-{stream_id}` stream names.
//!
//! ## Guarantees
//!
//! - **At-least-once delivery, idempotent appends** — reactor outputs carry
//!   deterministic `event_id`s, so crash-redelivery dedups on append.
//! - **Replay determinism** — no wall-clock inside consumer bodies;
//!   aggregate state is a pure fold of the log.
//! - **Quiescence** — `emit(...).settled()` resolves when the event's
//!   correlation chain has been observed by every consumer.
//! - **OCC where you opt in** — the `Engine::append` decider path enforces
//!   [`StreamState`] expectations with typed conflicts.
//!
//! ## Example
//!
//! ```
//! use std::sync::Arc;
//! use causal::{
//!     CheckpointStore, Ctx, EngineBuilder, Event, EventLogBackend,
//!     Events, MemoryStore, Reactor, ReactorCheckpoint,
//! };
//! use serde::{Deserialize, Serialize};
//! use uuid::Uuid;
//!
//! #[derive(Debug, Clone, Serialize, Deserialize)]
//! struct OrderPlaced { order_id: Uuid, total: f64 }
//!
//! impl Event for OrderPlaced {
//!     const CATEGORY: &'static str = "order";
//!     fn event_type(&self) -> &str { "placed" }
//!     fn stream_id(&self) -> Uuid { self.order_id }
//! }
//!
//! #[derive(Debug, Clone, Serialize, Deserialize)]
//! struct ShipmentRequested { order_id: Uuid }
//!
//! impl Event for ShipmentRequested {
//!     const CATEGORY: &'static str = "shipment";
//!     fn event_type(&self) -> &str { "requested" }
//!     fn stream_id(&self) -> Uuid { self.order_id }
//! }
//!
//! struct ShipOnPlaced;
//!
//! #[async_trait::async_trait]
//! impl Reactor for ShipOnPlaced {
//!     type Trigger = OrderPlaced;
//!     const GROUP_NAME: &'static str = "ship_on_placed";
//!
//!     async fn react(&self, t: &OrderPlaced, _ctx: Ctx<'_>) -> anyhow::Result<Events> {
//!         Ok(causal::events![ShipmentRequested { order_id: t.order_id }])
//!     }
//! }
//!
//! # fn main() -> anyhow::Result<()> {
//! # tokio::runtime::Runtime::new()?.block_on(async {
//! let store = Arc::new(MemoryStore::new());
//! let engine = EngineBuilder::new(
//!         store.clone() as Arc<dyn EventLogBackend>,
//!         store.clone() as Arc<dyn CheckpointStore>,
//!         store.clone() as Arc<dyn ReactorCheckpoint>,
//!     )
//!     .with_reactor(ShipOnPlaced)
//!     .build()
//!     .await?;
//!
//! // Persists the event, stamps causation/correlation, and resolves once
//! // ShipOnPlaced has reacted and its output has landed in the log.
//! engine.emit(OrderPlaced { order_id: Uuid::new_v4(), total: 99.99 })
//!     .settled()
//!     .await?;
//! # anyhow::Ok(())
//! # })
//! # }
//! ```
//!
//! The `#[event]` macro (feature `macros`, on by default) generates the
//! [`Event`] impl from an enum; the example hand-rolls it to show the
//! full trait surface.

extern crate self as causal;

// Module structure
pub mod aggregate;
pub mod aggregator;
pub mod checkpoint_store;
pub mod contexts;
pub mod engine;
pub mod event_log;
pub mod event_type;
pub mod event;
pub mod multi_projector;
pub mod projection;
pub mod projection_runner;
pub mod projector;
pub mod reaction_cache;
pub mod reactor_observer;
pub mod reactor_runner;
pub mod reactor;
pub mod snapshot_store;
pub mod types;

pub mod memory_store;

// ── public surface ──────────────────────────────────────────────
//
// What's in the prelude vs. behind a module path follows one rule:
// **the prelude is for what a user types in normal application code**.
//
// User-facing (here): facts, aggregates, consumer traits, the engine,
// the emit builder, registration trait objects, context types,
// cursors/versions, backend traits (cast at builder time), MemoryStore,
// macros.
//
// Backend-impl-facing (module paths only): EventData, WriteResult,
// Snapshot — backends pull these from `causal::types::*` directly.
// Same for runners (`causal::projection_runner::*`) and the
// checkpoint / reactor-checkpoint traits (`causal::checkpoint_store::*`).
//
// Internal-detail (module paths only): EventOutput (Events
// implementation detail), EmitInput (Into-target only),
// AggregatorRegistry (engine-internal state), extract_prefix
// (replaced by RecordedEvent::category() for the common case).

// Facts + aggregates
pub use event::{event_type_for, stream_name_for, Event};
pub use aggregate::{Aggregate, Apply};
pub use aggregator::Aggregator;

// Consumers
pub use projector::Projector;
pub use multi_projector::MultiProjector;
pub use reactor::{Events, Reactor};

// Engine + emit
pub use engine::{
    Engine, EngineBuilder,
    EmitBuilder, EmitResult, SettledEmit,
    DlqInfo,
    MultiProjectorRegistration, ProjectorRegistration, ReactorRegistration,
};

// Context
pub use contexts::{AggregateState, Ctx, Metadata};

// Cursors / revisions / values users see in signatures
pub use types::{
    WriteResult, EventData, LogCursor, LogEntry, LogLevel, RecordedEvent,
    StreamRevision, StreamState,
};

// Observability hook
pub use reactor_observer::{NoopObserver, ReactorObserver};

// Reactor idempotency (Phase 4 foundation): memoize side-effecting
// reactions so at-least-once delivery is safe; deterministic emit ids.
pub use reaction_cache::{remember, InMemoryReactionCache, ReactionCache, ReactionKey};

// Backend traits (users typically cast `Arc<dyn ...>` at builder time)
pub use checkpoint_store::{CheckpointStore, ReactorCheckpoint};
pub use event_log::{append_event, EventLogBackend};
pub use projection::StartPosition;
pub use snapshot_store::SnapshotStore;

// Default backend
pub use memory_store::MemoryStore;


/// Universal return macro for [`Reactor::react`]. Builds an
/// [`Events`] collection from one or more output facts.
///
/// ```ignore
/// Ok(events![])                                  // no outputs
/// Ok(events![OrderShipped { order_id }])         // one output
/// Ok(events![ScrapeEvent { .. }, Lifecycle::..]) // many
/// Ok(events![..items])                           // fan-out batch
/// ```
#[macro_export]
macro_rules! events {
    () => {
        $crate::Events::new()
    };
    (.. $spread:expr) => {
        $crate::Events::batch($spread)
    };
    ($single:expr $(,)?) => {{
        let mut __ev = $crate::Events::new();
        __ev.push($single);
        __ev
    }};
    ($($event:expr),+ $(,)?) => {{
        let mut __ev = $crate::Events::new();
        $(__ev.push($event);)+
        __ev
    }};
}

#[cfg(feature = "macros")]
pub use causal_core_macros::{aggregators, event};

