//! deeplossless — Lossless Context Management proxy for DeepSeek API.
//!
//! # Architecture Invariants
//!
//! ## DAG Direction (P0)
//!
//! A summary node stores its source (raw) node IDs in `child_ids`:
//!
//! ```text
//! summary.child_ids = [raw_1, raw_2, ...]
//! ```
//!
//! Conversely, each source node stores the summary ID in `parent_ids`:
//!
//! ```text
//! raw_n.parent_ids = [summary]
//! ```
//!
//! Edge direction: **raw → summary** (summarization flows from sources upward).
//! Nodes may have multiple parents via `Refines` and `Reuses` edges, forming a
//! true DAG. Cross-conversation sharing is enabled when embedding similarity
//! exceeds threshold, creating `Reuses` edges across conversation boundaries.
//!
//! - `get_children(node)` returns the nodes in `node.child_ids` (forward lookup)
//! - `get_parents(node)` returns nodes whose `child_ids` contains `node.id`
//!
//! ## Coverage Invariant (P0)
//!
//! A summary's coverage = the set of raw message IDs in its `child_ids`.
//! Context assembly (`assemble_context`) MUST NOT inject a raw leaf that
//! is already covered by any selected summary, preventing double injection.
//!
//! ## Level Invariant (P0)
//!
//! | Level | Name       | is_leaf | Content               |
//! |-------|------------|---------|-----------------------|
//! | 0     | Raw leaf   | true    | Original message text |
//! | 1     | L1 summary | false   | LLM preserve_details  |
//! | 2     | L2 summary | false   | LLM bullet_points     |
//! | 3+    | L3+ summary| false   | Deterministic/aggr.   |
//!
//! ## Snippet Authority (P1)
//!
//! Snippets extracted before compression are stored on the summary node
//! and take precedence over the summary text for precision-critical values
//! (code blocks, file paths, numeric constants, error messages).
//!
//! ## GC Reachability (P1)
//!
//! A node is reachable iff traversable from any tip or leaf via BFS along
//! BOTH `parent_ids` (raw → summary) and `child_ids` (summary → raw).
//! Unreachable nodes ("ghosts") are candidates for deletion.
//!
//! ## Assembly Invariant (P1)
//!
//! Context assembly output must stay within `token_budget`. No leaf
//! covered by a selected summary shall appear as a raw leaf.
//!
//! ## Transaction Invariant (P2)
//!
//! DAG mutations (insert node + back-link to sources) must be atomic.
//! A database transaction wraps both operations.

#![allow(clippy::too_many_arguments)]

pub mod compactor;
pub mod dag;
pub mod db;
pub mod embeddings;
pub mod artifacts;
pub mod execution;
pub mod runtime;
pub mod tool_cache;
pub mod metrics;
pub mod pipeline;
pub mod protocol;
pub mod proxy;
pub mod session;
pub mod snapshot;
pub mod snippet;
pub mod summarizer;
pub mod tokenizer;

use std::sync::Arc;
use std::sync::Mutex as StdMutex;
use tokio::sync::Mutex;
use std::collections::HashMap;

#[derive(Clone)]
pub struct AppState {
    pub upstream: String,
    /// API key extracted from the first incoming request's Authorization header.
    /// `None` until the first request arrives. The compactor/spawner reads this
    /// for background summarization calls.
    pub api_key: Arc<StdMutex<Option<String>>>,
    /// Separate admin key for LCM endpoint authentication. If set, takes
    /// priority over `api_key` for LCM auth. If unset, LCM falls back to
    /// `api_key` for backward compatibility.
    pub admin_key: Arc<StdMutex<Option<String>>>,
    pub db: Arc<db::Database>,
    pub dag: Arc<dag::DagEngine>,
    pub compactor: Arc<Mutex<compactor::Compactor>>,
    pub client: reqwest::Client,
    /// Model used for background summarization (configurable via CLI/env).
    pub summarizer_model: String,
    /// Runtime cycle tracking for policy-driven execution.
    pub cycle: Arc<StdMutex<runtime::ExecutionCycle>>,
    /// When true, skip upstream calls — save translated body to disk and return mock response.
    pub dry_run: bool,
    /// Completed response objects keyed by response ID. Enables
    /// `previous_response_id` continuity so Codex can do incremental turns
    /// instead of rebuilding full context on every request.
    pub response_store: Arc<StdMutex<HashMap<String, serde_json::Value>>>,
    /// When set, enables per-request JSON logging to this directory.
    /// Each request writes one JSON line to a timestamped .jsonl file.
    pub log_dir: Option<String>,
}

impl AppState {
    pub fn summarizer_model(&self) -> &str {
        &self.summarizer_model
    }
}
