//! Application state shared across all request handlers.

use std::sync::Arc;
use tokio::sync::{Mutex, Notify};

use stemedb_query::QueryEngine;
use stemedb_storage::{
    CircuitBreakerConfig, GenericAdmissionStore, GenericAliasStore, GenericApiKeyStore,
    GenericCircuitBreakerStore, GenericEscalationStore, GenericQuarantineStore, GenericQuotaStore,
    GenericTrustRankStore, HybridStore,
};
use stemedb_wal::group_commit::{GroupCommitBuffer, GroupCommitConfig};
use stemedb_wal::Journal;

#[cfg(feature = "aphoria")]
use crate::scan_cache::ScanCache;

/// 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>>;

/// Trust rank store type alias for convenience.
pub type TrustRankStoreImpl = GenericTrustRankStore<Arc<HybridStore>>;

/// Admission store type alias for convenience.
pub type AdmissionStoreImpl = GenericAdmissionStore<Arc<TrustRankStoreImpl>>;

/// Quarantine store type alias for convenience.
pub type QuarantineStoreImpl = GenericQuarantineStore<HybridStore>;

/// Circuit breaker store type alias for convenience.
pub type CircuitBreakerStoreImpl = GenericCircuitBreakerStore<HybridStore>;

/// API key store type alias for convenience.
pub type ApiKeyStoreImpl = GenericApiKeyStore<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>,

    /// Trust rank store for reputation tracking
    pub trust_rank_store: Arc<TrustRankStoreImpl>,

    /// Admission store for PoW-based admission control (The Shield)
    pub admission_store: Arc<AdmissionStoreImpl>,

    /// Quarantine store for content defense (Phase 7C)
    pub quarantine_store: Arc<QuarantineStoreImpl>,

    /// Circuit breaker store for misbehavior isolation (Phase 7D)
    pub circuit_breaker_store: Arc<CircuitBreakerStoreImpl>,

    /// API key store for authentication (P4.2)
    pub api_key_store: Arc<ApiKeyStoreImpl>,

    /// Notification channel for signaling IngestWorker when new data is flushed.
    ///
    /// When GroupCommitBuffer successfully flushes a batch, it signals this
    /// Notify so IngestWorker can immediately refresh and process new records.
    pub flush_notify: Arc<Notify>,

    /// Scan cache for Aphoria scan history (feature-gated).
    #[cfg(feature = "aphoria")]
    pub scan_cache: ScanCache,
}

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.
    ///
    /// Creates a shared notification channel that GroupCommitBuffer uses
    /// to signal IngestWorker when new data is flushed.
    pub fn new(write_journal: Journal, read_journal: Journal, store: Arc<HybridStore>) -> Self {
        // Create shared notification channel for WAL flush -> IngestWorker signaling
        let flush_notify = Arc::new(Notify::new());

        // Build commit buffer with flush notification
        let commit_buffer = GroupCommitBuffer::builder(write_journal, GroupCommitConfig::default())
            .with_flush_notify(Arc::clone(&flush_notify))
            .build();

        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)));

        // Create trust rank store for reputation tracking
        let trust_rank_store = Arc::new(GenericTrustRankStore::new(Arc::clone(&store)));

        // Create admission store for PoW-based admission control
        let admission_store = Arc::new(GenericAdmissionStore::new(Arc::clone(&trust_rank_store)));

        // Create quarantine store for content defense
        let quarantine_store = Arc::new(GenericQuarantineStore::new(Arc::clone(&store)));

        // Create circuit breaker store for misbehavior isolation
        let circuit_breaker_store = Arc::new(GenericCircuitBreakerStore::new(
            Arc::clone(&store),
            CircuitBreakerConfig::default(),
        ));

        // Create API key store for authentication (P4.2)
        let api_key_store = Arc::new(GenericApiKeyStore::new(Arc::clone(&store)));

        Self {
            commit_buffer,
            journal,
            store,
            quota_store,
            escalation_store,
            alias_store,
            trust_rank_store,
            admission_store,
            quarantine_store,
            circuit_breaker_store,
            api_key_store,
            flush_notify,
            #[cfg(feature = "aphoria")]
            scan_cache: ScanCache::new(),
        }
    }

    /// 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())
    }
}
