//! # MicroResolve
//!
//! Sub-millisecond intent resolution. No embeddings, no GPU, no retraining.
//! Scoring layers (morphology graph + scoring index) are in `src/scoring.rs`.
//!
//! ## Quick Start
//!
//! ```
//! use microresolve::{MicroResolve, MicroResolveConfig};
//!
//! let engine = MicroResolve::new(MicroResolveConfig::default()).unwrap();
//! let ns = engine.namespace("orders");
//! ns.add_intent("cancel_order", &["cancel my order", "stop my order"][..]).unwrap();
//! ns.add_intent("track_order",  &["where is my package", "track my order"][..]).unwrap();
//!
//! let result = ns.resolve("I want to cancel");
//! assert_eq!(result.intents[0].id, "cancel_order");
//! ```

// Internal layers — kept `pub` because the server bin (a separate crate
// target) reaches into them directly, but `#[doc(hidden)]` keeps them out
// of rustdoc + IDE autocomplete. Library users go through `MicroResolve` +
// `NamespaceHandle`; these modules are not part of the semver surface.
#[doc(hidden)]
pub mod phrase;
#[doc(hidden)]
pub mod scoring;
#[doc(hidden)]
pub mod tokenizer;

pub mod import;
pub mod oplog;
pub mod types;

#[cfg(feature = "connect")]
#[doc(hidden)]
pub mod connect;

// Resolver method modules (each contains `impl Resolver { ... }`)
mod resolver_core;
mod resolver_intents;
mod resolver_learning;
mod resolver_metadata;
mod resolver_persist;

mod engine;
pub use engine::{
    Band, Disposition, IntentMatch, MicroResolve, NamespaceHandle, ResolveResult, ResolveTrace,
};

/// Default routing threshold (cascade fallback).
pub const DEFAULT_THRESHOLD: f32 = 1.0;
/// Default multi-intent gap multiplier.
pub const DEFAULT_GAP: f32 = 1.5;

pub(crate) type FxHashMap<K, V> = std::collections::HashMap<K, V, rustc_hash::FxBuildHasher>;
pub(crate) type FxHashSet<T> = std::collections::HashSet<T, rustc_hash::FxBuildHasher>;

pub use types::*;

use std::collections::HashMap;

/// Single entry in the L2b negative-training audit trail.
/// Internal — surfaced via the server's training endpoints; library users
/// don't construct these directly.
#[doc(hidden)]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct NegativeTrainingEntry {
    /// Unix seconds when the training call was applied.
    pub timestamp: u64,
    /// Number of benign/adversarial queries in the corpus.
    pub corpus_size: usize,
    /// Number of intents the weights were shrunk for.
    pub intents_affected: usize,
    /// Decay rate used. API clamps to (0.0, 0.3].
    pub alpha: f32,
}

pub use oplog::{Op, OPLOG_MAX};

/// Single-namespace primitive backing every [`NamespaceHandle`].
///
/// **Library users should not reach for this directly** — use [`MicroResolve`] +
/// [`NamespaceHandle`]. The type is kept `pub` only because the server
/// binary, which compiles as a separate crate target, needs it for now.
/// Treat as internal API: signatures may change without semver consideration.
#[doc(hidden)]
#[derive(Clone)]
pub struct Resolver {
    /// Scoring index: IDF-weighted word→intent associations with anti-Hebbian inhibition.
    pub(crate) index: crate::scoring::IntentIndex,
    /// Raw training phrases per intent, grouped by language code.
    /// Structure: { intent_id: { lang_code: [phrases] } }
    /// This is the canonical intent list — `intent_ids()` reads from here.
    training: HashMap<String, HashMap<String, Vec<String>>>,
    /// Human-readable description per intent.
    /// Used by LLM prompts for Hebbian bootstrap context.
    descriptions: HashMap<String, String>,
    /// LLM instructions per intent (what to do when this intent fires).
    instructions: HashMap<String, String>,
    /// LLM persona per intent (tone and voice).
    persona: HashMap<String, String>,
    /// Import provenance: where this intent's definition came from.
    sources: HashMap<String, IntentSource>,
    /// Execution target: where to send when this intent fires.
    targets: HashMap<String, IntentTarget>,
    /// Tool/API schema for imported intents (JSON Schema format).
    schemas: HashMap<String, serde_json::Value>,
    /// Guardrail rules for this intent.
    guardrails: HashMap<String, Vec<String>>,
    /// Monotonic version counter. Incremented on every mutation.
    version: u64,
    /// Human-readable display name for this namespace.
    namespace_name: String,
    /// Human-readable description of this namespace.
    namespace_description: String,
    /// Default routing threshold for this namespace.
    /// Used as fallback when /api/resolve requests omit `threshold`.
    /// `None` means "no override, use the compile-time default."
    /// `Some(0.0)` is a valid (degenerate) setting — accept all matches.
    namespace_default_threshold: Option<f32>,
    /// Default voting-token gate for this namespace.
    /// `None` means "no override, use the compile-time default (1 = disabled)."
    /// `Some(1)` explicitly disables; `Some(2)` or higher activates the gate.
    /// See `IntentIndex::min_voting_tokens` for behavior.
    namespace_default_min_voting_tokens: Option<u32>,
    /// Descriptions for domain prefixes (e.g., "billing" in "billing:cancel_order").
    domain_descriptions: HashMap<String, String>,
    /// Audit trail: history of every negative-training call applied to
    /// this namespace. Persisted in `_ns.json`. Use `rebuild_index()` + clear
    /// to undo. Rail 2 of three: visible action, reversible, bounded.
    negative_training_log: Vec<NegativeTrainingEntry>,
    /// Delta-sync oplog: bounded ring of (version, Op) pairs. Not persisted
    /// via serde — saved/loaded as `_oplog.json` alongside `_index.json`.
    #[doc(hidden)]
    pub oplog: std::collections::VecDeque<(u64, crate::oplog::Op)>,
}

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

// Resolver methods split across modules:
// resolver_core.rs      — constructor, persistence, accessors, resolve()
// resolver_intents.rs   — intent CRUD, phrase management
// resolver_learning.rs  — correct(), continuous learning
// resolver_metadata.rs  — intent types, descriptions, instructions, persona, sources, targets
// resolver_persist.rs   — directory-based persistence
