//! Per-command modules — one file per top-level subcommand.
//!
//! `main.rs` holds the clap surface (argument enums) and the dispatch
//! `match`; the actual command bodies live here. Helpers shared between
//! command modules (e.g. `commit_paths`, `resolve_query`) are defined in
//! this file as `pub(crate)` so siblings can pull them in via
//! `use crate::commands::*`.

pub mod add;
pub mod attach;
pub mod backup;
pub mod device;
pub mod edit;
pub mod generate;
pub mod get;
pub mod import;
pub mod item_build;
pub mod org;
pub mod init;
pub mod list;
pub mod rate;
pub mod recovery_qr;
pub mod settings;
pub mod status;
pub mod sync;
pub mod trash;

use anyhow::Result;

pub(crate) fn commit_paths(
    vault: &crate::session::UnlockedVault,
    message: &str,
    paths: &[&str],
) -> Result<()> {
    let mut args: Vec<&str> = vec!["add"];
    args.extend_from_slice(paths);
    crate::helpers::git_run(vault.root(), &args, &format!("commit \"{message}\": git add"))?;
    crate::helpers::git_run(
        vault.root(),
        &["commit", "-m", message],
        &format!("commit \"{message}\": git commit"),
    )?;
    Ok(())
}

pub(crate) fn resolve_query<'a>(
    manifest: &'a relicario_core::Manifest,
    query: &str,
) -> Result<&'a relicario_core::ManifestEntry> {
    if let Some(entry) = manifest.items.values().find(|e| e.id.as_str() == query) {
        return Ok(entry);
    }
    let hits: Vec<_> = manifest.search(query);
    match hits.len() {
        0 => anyhow::bail!("no item matches `{query}`"),
        1 => Ok(hits[0]),
        _ => {
            let titles: Vec<&str> = hits.iter().map(|e| e.title.as_str()).collect();
            anyhow::bail!("ambiguous — {} matches: {}", hits.len(), titles.join(", "))
        }
    }
}
