//! Application state shared across all request handlers.

use std::sync::Arc;
use tokio::sync::Mutex;

use stemedb_query::QueryEngine;
use stemedb_storage::{GenericAliasStore, GenericEscalationStore, GenericQuotaStore, HybridStore};
use stemedb_wal::group_commit::{GroupCommitBuffer, GroupCommitConfig};
use stemedb_wal::Journal;

/// Quota store type alias for convenience.
pub type QuotaStoreImpl = GenericQuotaStore<Arc<HybridStore>>;

/// Escalation store type alias for convenience.
pub type EscalationStoreImpl = GenericEscalationStore<HybridStore>;

/// Alias store type alias for convenience.
pub type AliasStoreImpl = GenericAliasStore<Arc<HybridStore>>;

/// Application state shared across all HTTP handlers.
///
/// This is passed to every request via axum's `State` extractor.
#[derive(Clone)]
pub struct AppState {
    /// Group commit buffer for batched WAL writes (used by write handlers)
    pub commit_buffer: GroupCommitBuffer,

    /// Write-ahead log for reading records (IngestWorker uses this)
    pub journal: Arc<Mutex<Journal>>,

    /// Key-value store for reading assertions
    pub store: Arc<HybridStore>,

    /// Quota store for economic throttling (The Meter)
    pub quota_store: Arc<QuotaStoreImpl>,

    /// Escalation store for high-conflict assertion tracking
    pub escalation_store: Arc<EscalationStoreImpl>,

    /// Alias store for cross-scheme entity resolution
    pub alias_store: Arc<AliasStoreImpl>,
}

impl AppState {
    /// Create a new application state.
    ///
    /// Takes two journals: one for the group commit buffer (writes) and
    /// one for reading (used by IngestWorker). Both should be opened on
    /// the same directory.
    pub fn new(write_journal: Journal, read_journal: Journal, store: Arc<HybridStore>) -> Self {
        let commit_buffer = GroupCommitBuffer::new(write_journal, GroupCommitConfig::default());
        let journal = Arc::new(Mutex::new(read_journal));

        // Create quota store backed by the same KV store
        let quota_store = Arc::new(GenericQuotaStore::new(Arc::clone(&store)));

        // Create escalation store backed by the same KV store
        let escalation_store = Arc::new(GenericEscalationStore::new(Arc::clone(&store)));

        // Create alias store for cross-scheme concept resolution
        let alias_store = Arc::new(GenericAliasStore::new(Arc::clone(&store)));

        Self { commit_buffer, journal, store, quota_store, escalation_store, alias_store }
    }

    /// Get a QueryEngine for this state.
    ///
    /// Creates a new QueryEngine each time since it cannot be cloned.
    pub fn query_engine(&self) -> QueryEngine<HybridStore> {
        QueryEngine::new(self.store.clone())
    }
}
