/// Typed representation of `.ontoref/config.ncl`.
///
/// Every section that the daemon reads from its own config file is captured
/// here with `#[derive(ConfigFields)]` so that `inventory` registers the
/// consumed fields at link time.  The coherence endpoint can then compare
/// these registrations against the live NCL export without needing a
/// hand-maintained `fields` list in `manifest.ncl`.
///
/// All fields carry `#[serde(default)]` — a project may omit any section and
/// the daemon degrades gracefully rather than failing to start.
use ontoref_ontology::ConfigFields;
use serde::Deserialize;

/// Full deserialized view of `.ontoref/config.ncl`.
#[derive(Debug, Deserialize, Default)]
pub struct DaemonNclConfig {
    #[serde(default)]
    pub nickel_import_paths: Vec<String>,
    #[serde(default)]
    pub ui: UiConfig,
    #[serde(default)]
    pub log: LogConfig,
    #[serde(default)]
    pub mode_run: ModeRunConfig,
    #[serde(default)]
    pub nats_events: NatsEventsConfig,
    #[serde(default)]
    pub actor_init: Vec<ActorInit>,
    #[serde(default)]
    pub quick_actions: Vec<QuickAction>,
    #[serde(default)]
    pub daemon: DaemonRuntimeConfig,
    #[serde(default)]
    pub ops: OpsConfig,
    #[cfg(feature = "db")]
    #[serde(default)]
    pub db: DbConfig,
    #[cfg(feature = "graphql")]
    #[serde(default)]
    pub graphql: GraphqlConfig,
}

// `ops` section — per-project tier and phase declaration. Types moved
// to `ontoref-ops::tier` so handler-side code can use them without
// depending on this crate. Re-exported here for backward compatibility.
pub use ontoref_ops::tier::{OpsConfig, Phase, Tier};

/// `ui` section — template and asset paths, optional TLS cert overrides.
#[derive(Debug, Deserialize, Default, ConfigFields)]
#[config_section(id = "ui", ncl_file = ".ontoref/config.ncl")]
pub struct UiConfig {
    #[serde(default)]
    pub templates_dir: String,
    #[serde(default)]
    pub public_dir: String,
    #[serde(default)]
    pub tls_cert: String,
    #[serde(default)]
    pub tls_key: String,
    #[serde(default)]
    pub logo: String,
    #[serde(default)]
    pub logo_dark: String,
}

/// `log` section — structured logging policy.
#[derive(Debug, Deserialize, ConfigFields)]
#[config_section(id = "log", ncl_file = ".ontoref/config.ncl")]
pub struct LogConfig {
    #[serde(default = "default_log_level")]
    pub level: String,
    #[serde(default = "default_log_path")]
    pub path: String,
    #[serde(default = "default_rotation")]
    pub rotation: String,
    #[serde(default)]
    pub compress: bool,
    #[serde(default = "default_log_archive")]
    pub archive: String,
    #[serde(default = "default_max_files")]
    pub max_files: u32,
}

impl Default for LogConfig {
    fn default() -> Self {
        Self {
            level: default_log_level(),
            path: default_log_path(),
            rotation: default_rotation(),
            compress: false,
            archive: default_log_archive(),
            max_files: default_max_files(),
        }
    }
}

fn default_log_level() -> String {
    "info".into()
}
fn default_log_path() -> String {
    "logs".into()
}
fn default_rotation() -> String {
    "daily".into()
}
fn default_log_archive() -> String {
    "logs-archive".into()
}
fn default_max_files() -> u32 {
    7
}

/// `nats_events` section — NATS JetStream integration.
#[derive(Debug, Deserialize, Default, ConfigFields)]
#[config_section(id = "nats_events", ncl_file = ".ontoref/config.ncl")]
pub struct NatsEventsConfig {
    #[serde(default)]
    pub enabled: bool,
    #[serde(default = "default_nats_url")]
    pub url: String,
    #[serde(default)]
    pub emit: Vec<String>,
    #[serde(default)]
    pub subscribe: Vec<String>,
    #[serde(default)]
    pub handlers_dir: String,
    #[serde(default)]
    pub nkey_seed: Option<String>,
    #[serde(default)]
    pub require_signed_messages: bool,
    #[serde(default)]
    pub trusted_nkeys: Vec<String>,
    #[serde(default)]
    pub streams_config: String,
}

fn default_nats_url() -> String {
    "nats://localhost:4222".into()
}

/// `mode_run` section — per-actor mode execution ACL.
#[derive(Debug, Deserialize, Default, ConfigFields)]
#[config_section(id = "mode_run", ncl_file = ".ontoref/config.ncl")]
pub struct ModeRunConfig {
    #[serde(default)]
    pub rules: Vec<ModeRunRule>,
}

#[derive(Debug, Deserialize, Default)]
pub struct ModeRunRule {
    #[serde(default)]
    pub when: ModeRunWhen,
    #[serde(default)]
    pub allow: bool,
    #[serde(default)]
    pub reason: String,
}

#[derive(Debug, Deserialize, Default)]
pub struct ModeRunWhen {
    #[serde(default)]
    pub mode_id: Option<String>,
    #[serde(default)]
    pub actor: Option<String>,
}

/// One entry in the `actor_init` array.
#[derive(Debug, Deserialize, Default)]
pub struct ActorInit {
    #[serde(default)]
    pub actor: String,
    #[serde(default)]
    pub mode: String,
    #[serde(default)]
    pub auto_run: bool,
}

/// One entry in the `quick_actions` array.
#[derive(Debug, Deserialize, Default)]
pub struct QuickAction {
    #[serde(default)]
    pub id: String,
    #[serde(default)]
    pub label: String,
    #[serde(default)]
    pub icon: String,
    #[serde(default)]
    pub category: String,
    #[serde(default)]
    pub mode: String,
    #[serde(default)]
    pub actors: Vec<String>,
}

/// `daemon` section — overrides for CLI defaults set at startup.
#[derive(Debug, Deserialize, Default, ConfigFields)]
#[config_section(id = "daemon", ncl_file = ".ontoref/config.ncl")]
pub struct DaemonRuntimeConfig {
    #[serde(default)]
    pub port: Option<u16>,
    #[serde(default)]
    pub idle_timeout: Option<u64>,
    #[serde(default)]
    pub invalidation_interval: Option<u64>,
    #[serde(default)]
    pub actor_sweep_interval: Option<u64>,
    #[serde(default)]
    pub actor_stale_timeout: Option<u64>,
    #[serde(default)]
    pub max_notifications: Option<usize>,
    #[serde(default)]
    pub notification_ack_required: Vec<String>,
}

/// `graphql` section — GraphQL endpoint access control (feature-gated).
///
/// `read_token_hash` is an argon2id PHC string produced by
/// `ontoref-daemon --hash-password <token>`. Empty string disables auth.
#[cfg(feature = "graphql")]
#[derive(Debug, Deserialize, Default, ConfigFields)]
#[config_section(id = "graphql", ncl_file = ".ontoref/config.ncl")]
pub struct GraphqlConfig {
    /// Argon2id PHC hash of the read token. Empty = no auth required.
    #[serde(default)]
    pub read_token_hash: String,
}

/// `db` section — SurrealDB connection (feature-gated).
#[cfg(feature = "db")]
#[derive(Debug, Deserialize, Default, ConfigFields)]
#[config_section(id = "db", ncl_file = ".ontoref/config.ncl")]
pub struct DbConfig {
    #[serde(default)]
    pub enabled: bool,
    #[serde(default)]
    pub url: String,
    #[serde(default)]
    pub namespace: String,
    #[serde(default)]
    pub username: String,
    #[serde(default)]
    pub password: String,
}
