//! Shared application state handed to every axum handler and the sync worker.

use crate::db::sqlite::SharedSqlite;
use deadpool_postgres::Pool;
use roundabout_orm_schema::EntityDef;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::broadcast;

/// A live alert pushed to WebSocket subscribers after a field change reaches PG.
pub type WsHub = Arc<HashMap<String, broadcast::Sender<String>>>;

#[derive(Clone)]
pub struct AppState {
    /// Postgres pool (the read side, and the worker's write target).
    pub pg: Pool,
    /// SQLite write-staging store.
    pub sqlite: SharedSqlite,
    /// Loaded schema, shared read-only.
    pub manifest: Arc<Vec<EntityDef>>,
    /// Broadcast senders keyed by table, one per entity that has a `ws` field.
    pub ws_hub: WsHub,
    /// OpenAPI spec built once from the manifest, served at `/openapi.json`.
    pub openapi: Arc<serde_json::Value>,
}

/// Build a [`WsHub`] with a channel for every entity exposing a live field.
pub fn build_hub(manifest: &[EntityDef]) -> WsHub {
    let mut map = HashMap::new();
    for ent in manifest {
        if ent.has_ws() {
            let (tx, _rx) = broadcast::channel::<String>(256);
            map.insert(ent.table.clone(), tx);
        }
    }
    Arc::new(map)
}
