//! Registry-backed HTTP+NATS daemon for the provisioning platform.
//!
//! Wraps `provisioning-core::Registry` in an Axum HTTP server with JWT auth,
//! RBAC, NATS event publication, domain-state tracking, and config-file watching.

pub mod auth;
pub mod domain_state;
pub mod events;
pub mod http;
pub mod ontology;
pub mod ui;
pub mod watcher;

use provisioning_core::{Environment, Registry};
use std::{path::PathBuf, sync::Arc};
use ui::session::SessionStore;

/// Shared application state injected into every Axum handler via `State`.
#[derive(Clone)]
pub struct AppState {
    pub registry: Arc<Registry>,
    pub env: Arc<Environment>,
    pub state: domain_state::DomainState,
    /// Present when NATS is configured.
    pub bus: Option<events::EventBus>,
    /// Present when JWT is enabled (absent in solo mode).
    pub jwt: Option<auth::JwtConfig>,
    /// Present when ontology document templates were loaded successfully.
    pub ontology: Option<Arc<ontology::OntologyRenderer>>,
    /// Present when the Tera SSR admin UI was built successfully.
    pub ui: Option<Arc<ui::UiRenderer>>,
    pub project_name: String,
    /// Root of the provisioning repo on disk (for .ontology/, reflection/, etc.).
    pub project_root: Option<Arc<PathBuf>>,
    /// NICKEL_IMPORT_PATH passed to `nickel export` invocations.
    pub nickel_import_path: Option<Arc<str>>,
    /// Path to the `provisioning` CLI binary for mode execution.
    pub provisioning_bin: Option<Arc<str>>,
    /// UI session store (in-memory, reset on restart).
    pub sessions: SessionStore,
    /// Static password for solo/dev UI login (absent = any non-empty string accepted in open mode).
    pub ui_password: Option<Arc<str>>,
    /// Control-center URL for delegated auth verification.
    pub control_center_url: Option<Arc<str>>,
}

impl AppState {
    pub fn new(registry: Registry, env: Environment) -> Self {
        Self {
            registry: Arc::new(registry),
            env: Arc::new(env),
            state: domain_state::DomainState::new(),
            bus: None,
            jwt: None,
            ontology: None,
            ui: None,
            project_name: "provisioning".into(),
            project_root: None,
            nickel_import_path: None,
            provisioning_bin: None,
            sessions: SessionStore::default(),
            ui_password: None,
            control_center_url: None,
        }
    }

    pub fn with_bus(mut self, bus: events::EventBus) -> Self {
        self.bus = Some(bus);
        self
    }

    pub fn with_jwt(mut self, jwt: auth::JwtConfig) -> Self {
        self.jwt = Some(jwt);
        self
    }

    pub fn with_ontology(mut self, renderer: ontology::OntologyRenderer) -> Self {
        self.ontology = Some(Arc::new(renderer));
        self
    }

    pub fn with_ui(mut self, renderer: ui::UiRenderer) -> Self {
        self.ui = Some(Arc::new(renderer));
        self
    }

    pub fn with_project_name(mut self, name: impl Into<String>) -> Self {
        self.project_name = name.into();
        self
    }

    pub fn with_project_root(mut self, root: PathBuf) -> Self {
        self.project_root = Some(Arc::new(root));
        self
    }

    pub fn with_nickel_import_path(mut self, path: impl Into<Arc<str>>) -> Self {
        self.nickel_import_path = Some(path.into());
        self
    }

    pub fn with_provisioning_bin(mut self, bin: impl Into<Arc<str>>) -> Self {
        self.provisioning_bin = Some(bin.into());
        self
    }

    pub fn with_ui_password(mut self, password: impl Into<Arc<str>>) -> Self {
        self.ui_password = Some(password.into());
        self
    }

    pub fn with_control_center_url(mut self, url: impl Into<Arc<str>>) -> Self {
        self.control_center_url = Some(url.into());
        self
    }

    pub fn with_session_persistence(mut self, file: PathBuf) -> Self {
        self.sessions = ui::session::SessionStore::with_persistence(file);
        self
    }
}
