//! Read/write helpers for the five LWW-map CRDT collections:
//! `tokens`, `merge_jobs`, `active_agents`, `test_jobs`, and `agent_throttle`.
//!
//! Each collection is backed by a `ListCrdt` with a primary-key field.
//! A secondary index in [`super::state::CrdtState`] provides O(1) lookup by
//! key.  The write functions follow the same insert-or-update pattern used by
//! [`super::presence`] for the `nodes` collection.

#![allow(dead_code)]

use bft_json_crdt::json_crdt::CrdtNode;
use bft_json_crdt::list_crdt::ListCrdt;
use bft_json_crdt::op::OpId;

mod active_agents;
mod agent_throttle;
mod event_log;
mod gateway_projects;
mod llm_sessions;
mod merge_jobs;
mod test_jobs;
mod tokens;

#[cfg(test)]
mod tests;

pub use active_agents::{
    delete_active_agent, read_active_agent, read_all_active_agents, write_active_agent,
};
pub use agent_throttle::{
    delete_agent_throttle, read_agent_throttle, read_all_agent_throttles, write_agent_throttle,
};
pub use event_log::{
    EventLogEntryRaw, GAP_PIPELINE_EVENT, append_event_log_entry, append_gap_log_entry,
    read_all_event_log_entries,
};
pub use gateway_projects::{
    delete_gateway_project, read_all_gateway_projects, read_gateway_project, write_gateway_project,
};
pub use llm_sessions::{assemble_and_advance_session, read_llm_session, write_llm_session};
pub use merge_jobs::{delete_merge_job, read_all_merge_jobs, read_merge_job, write_merge_job};
pub use test_jobs::{delete_test_job, read_all_test_jobs, read_test_job, write_test_job};
pub use tokens::{delete_token_usage, read_all_token_usage, read_token_usage, write_token_usage};

/// Return the `OpId` of the entry at iter-position `idx`, consistent with
/// `ListCrdt::iter()` and the `[]` index operator.
///
/// The built-in `id_at` counts non-deleted entries including the root sentinel
/// (which has `content = None`), causing an off-by-one mismatch with
/// `iter().enumerate()`.  This helper requires `content.is_some()` so that the
/// secondary-index position maps correctly to an OpId.
pub(super) fn list_id_at<T: CrdtNode>(list: &ListCrdt<T>, idx: usize) -> Option<OpId> {
    let mut i = 0;
    for op in &list.ops {
        if !op.is_deleted && op.content.is_some() {
            if i == idx {
                return Some(op.id);
            }
            i += 1;
        }
    }
    None
}
