//! Boolean Meta-sentinel helpers and the `Storage` methods that expose them.
//!
//! Sentinels: `needs_reindex`, `index_in_progress`.
//! All stored as `"true"` / `"false"` strings in the `Meta` relation.

use std::collections::BTreeMap;

use ckg_core::Result;
use cozo::{DataValue, DbInstance, ScriptMutability};

use super::map_err;

/// CR-I-2: shared helper for boolean Meta sentinels. Used by
/// `stamp_needs_reindex` and the `index_in_progress` sentinel.
pub(super) fn stamp_meta_bool(db: &DbInstance, key: &str, value: bool) -> Result<()> {
    let mut params = BTreeMap::new();
    params.insert("k".into(), DataValue::from(key));
    params.insert(
        "v".into(),
        DataValue::from(if value { "true" } else { "false" }),
    );
    db.run_script(
        "?[key, value] <- [[$k, $v]] :put Meta {key => value}",
        params,
        ScriptMutability::Mutable,
    )
    .map_err(map_err)?;
    Ok(())
}

/// CR-I-2: read a boolean Meta sentinel. Returns false on any read
/// failure (best-effort sentinel; not a correctness gate).
pub(super) fn read_meta_bool(db: &DbInstance, key: &str) -> bool {
    let mut params = BTreeMap::new();
    params.insert("k".into(), DataValue::from(key));
    let res = db.run_script(
        "?[v] := *Meta{key: $k, value: v}",
        params,
        ScriptMutability::Immutable,
    );
    match res {
        Ok(rows) => matches!(
            rows.rows.first().and_then(|r| r.first()),
            Some(DataValue::Str(s)) if s.as_str() == "true"
        ),
        Err(e) => {
            // M11: surface read errors so operators can diagnose.
            tracing::warn!(key, err = %e, "read_meta_bool failed; defaulting to false");
            false
        }
    }
}

/// Stamp the `needs_reindex` sentinel after a schema-version rebuild.
/// Cleared on first successful `ckg index` via `mark_indexed`.
pub(super) fn stamp_needs_reindex(db: &DbInstance, value: bool) -> Result<()> {
    stamp_meta_bool(db, "needs_reindex", value)
}
