use std::path::Path;
use cellos_sink_spool::bundle::{self, AuditBundle};
use crate::exit::{CtlError, CtlResult};
pub fn export_bundle(
dir: &Path,
chain_id: &str,
from_seq: u64,
to_seq: Option<u64>,
out: &Path,
) -> CtlResult<()> {
let bundle = bundle::export_bundle(dir, chain_id, from_seq, to_seq)
.map_err(|e| CtlError::validation(format!("export-bundle: {e}")))?;
let json = serde_json::to_string_pretty(&bundle)
.map_err(|e| CtlError::validation(format!("export-bundle: serialize: {e}")))?;
std::fs::write(out, json)
.map_err(|e| CtlError::usage(format!("export-bundle: write {}: {e}", out.display())))?;
let m = &bundle.manifest;
println!(
"exported {} rows [seq {}..={}] of chain {} to {}",
m.row_count,
m.from_seq,
m.to_seq,
m.chain_id,
out.display()
);
Ok(())
}
pub fn import_bundle(dir: &Path, input: &Path) -> CtlResult<()> {
let raw = std::fs::read_to_string(input)
.map_err(|e| CtlError::usage(format!("import-bundle: read {}: {e}", input.display())))?;
let bundle: AuditBundle = serde_json::from_str(&raw)
.map_err(|e| CtlError::validation(format!("import-bundle: parse bundle: {e}")))?;
let appended = bundle::import_bundle(dir, &bundle)
.map_err(|e| CtlError::validation(format!("import-bundle: {e}")))?;
println!("imported {appended} rows into {}", dir.display());
Ok(())
}
pub fn verify_chain(dir: &Path) -> CtlResult<()> {
let status =
bundle::verify_chain(dir).map_err(|e| CtlError::usage(format!("verify-chain: {e}")))?;
if status.ok {
match status.verified_high_seq {
Some(high) => println!(
"chain OK: verified seq 0..={high} (head {})",
status.head_row_hash
),
None => println!("chain OK: empty chain"),
}
Ok(())
} else {
let gap = status.gap.as_deref().unwrap_or("unknown break");
let high = status
.verified_high_seq
.map_or_else(|| "none".to_string(), |s| s.to_string());
eprintln!("cellctl: assertion: chain FAILED: {gap} (verified high seq: {high})");
std::process::exit(axiom_exit::Exit::AssertionFailed.code().into())
}
}