//! Application state for Córtex API

use aingle_graph::GraphDB;
use aingle_logic::RuleEngine;
use std::sync::Arc;
use tokio::sync::RwLock;

#[cfg(feature = "auth")]
use crate::auth::UserStore;
use crate::proofs::ProofStore;

/// Shared application state
#[derive(Clone)]
pub struct AppState {
    /// Graph database instance
    pub graph: Arc<RwLock<GraphDB>>,
    /// Logic validation engine
    pub logic: Arc<RwLock<RuleEngine>>,
    /// Event broadcaster for subscriptions
    pub broadcaster: Arc<EventBroadcaster>,
    /// Proof storage and verification
    pub proof_store: Arc<ProofStore>,
    /// User store for authentication
    #[cfg(feature = "auth")]
    pub user_store: Arc<UserStore>,
}

impl AppState {
    /// Create new application state with in-memory graph
    pub fn new() -> Self {
        let graph = GraphDB::memory().expect("Failed to create in-memory graph");
        let logic = RuleEngine::new();

        #[cfg(feature = "auth")]
        let user_store = {
            let store = Arc::new(UserStore::new());
            // Initialize default admin user
            let _ = store.init_default_admin();
            store
        };

        Self {
            graph: Arc::new(RwLock::new(graph)),
            logic: Arc::new(RwLock::new(logic)),
            broadcaster: Arc::new(EventBroadcaster::new()),
            proof_store: Arc::new(ProofStore::new()),
            #[cfg(feature = "auth")]
            user_store,
        }
    }

    /// Create with existing graph database
    pub fn with_graph(graph: GraphDB) -> Self {
        let logic = RuleEngine::new();

        #[cfg(feature = "auth")]
        let user_store = {
            let store = Arc::new(UserStore::new());
            // Initialize default admin user
            let _ = store.init_default_admin();
            store
        };

        Self {
            graph: Arc::new(RwLock::new(graph)),
            logic: Arc::new(RwLock::new(logic)),
            broadcaster: Arc::new(EventBroadcaster::new()),
            proof_store: Arc::new(ProofStore::new()),
            #[cfg(feature = "auth")]
            user_store,
        }
    }

    /// Get statistics
    pub async fn stats(&self) -> GraphStats {
        let graph = self.graph.read().await;
        let stats = graph.stats();
        GraphStats {
            triple_count: stats.triple_count,
            subject_count: stats.subject_count,
            predicate_count: stats.predicate_count,
            object_count: stats.object_count,
            connected_clients: self.broadcaster.client_count(),
        }
    }
}

impl Default for AppState {
    fn default() -> Self {
        Self::new()
    }
}

/// Graph statistics
#[derive(Debug, Clone, serde::Serialize)]
pub struct GraphStats {
    pub triple_count: usize,
    pub subject_count: usize,
    pub predicate_count: usize,
    pub object_count: usize,
    pub connected_clients: usize,
}

/// Event broadcaster for real-time updates
pub struct EventBroadcaster {
    /// Broadcast channel sender
    sender: tokio::sync::broadcast::Sender<Event>,
    /// Client count
    client_count: std::sync::atomic::AtomicUsize,
}

impl EventBroadcaster {
    /// Create new broadcaster
    pub fn new() -> Self {
        let (sender, _) = tokio::sync::broadcast::channel(1024);
        Self {
            sender,
            client_count: std::sync::atomic::AtomicUsize::new(0),
        }
    }

    /// Subscribe to events
    pub fn subscribe(&self) -> tokio::sync::broadcast::Receiver<Event> {
        self.client_count
            .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
        self.sender.subscribe()
    }

    /// Unsubscribe
    pub fn unsubscribe(&self) {
        self.client_count
            .fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
    }

    /// Broadcast event
    pub fn broadcast(&self, event: Event) {
        let _ = self.sender.send(event);
    }

    /// Get connected client count
    pub fn client_count(&self) -> usize {
        self.client_count.load(std::sync::atomic::Ordering::SeqCst)
    }
}

impl Default for EventBroadcaster {
    fn default() -> Self {
        Self::new()
    }
}

/// Event types for subscriptions
#[derive(Debug, Clone, serde::Serialize)]
#[serde(tag = "type", content = "data")]
pub enum Event {
    /// Triple was added
    TripleAdded {
        hash: String,
        subject: String,
        predicate: String,
        object: serde_json::Value,
    },
    /// Triple was deleted
    TripleDeleted { hash: String },
    /// Validation completed
    ValidationCompleted {
        hash: String,
        valid: bool,
        proof_hash: Option<String>,
    },
    /// Connection established
    Connected { client_id: String },
    /// Heartbeat
    Ping,
}

impl Event {
    /// Convert to JSON string
    pub fn to_json(&self) -> String {
        serde_json::to_string(self).unwrap_or_default()
    }
}
