use super::phase_map::{phase_to_u64, u64_to_label};
use super::progress_state::SharedProgress;
use crate::commands::format::format_with_commas;
use crate::commands::reindex_ui::ReindexPhase;
use indicatif::ProgressBar;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use tokio::task::JoinHandle;
pub(super) fn spawn_ticker(
progress: SharedProgress,
stats_bar: ProgressBar,
tick_done: Arc<AtomicBool>,
) -> JoinHandle<()> {
tokio::spawn(async move {
let started = progress.started;
let mut interval = tokio::time::interval(Duration::from_secs(1));
interval.tick().await; loop {
interval.tick().await;
if tick_done.load(Ordering::Acquire) {
break;
}
let elapsed = started.elapsed().as_secs();
let indexed = progress.indexed_now.load(Ordering::Acquire);
let chunks = progress
.chunks_now
.load(Ordering::Acquire)
.max(progress.chunks_embed_preview.load(Ordering::Acquire));
let skipped = progress.skipped_now.load(Ordering::Acquire);
let cps = progress.cps_now.load(Ordering::Acquire);
let total = progress.total_files_now.load(Ordering::Acquire);
let phase = progress.phase_disc.load(Ordering::Acquire);
let is_model_loading = phase == phase_to_u64(ReindexPhase::InitializingEmbedder);
let fps = indexed.checked_div(elapsed).unwrap_or(0);
let eta = if is_model_loading {
"loading model\u{2026}".to_string()
} else if fps > 0 && total > indexed {
crate::commands::format::fmt_secs((total - indexed) / fps)
} else {
"?".to_string()
};
let phase_label = u64_to_label(phase);
let cps_label = if cps > 0 {
format!("{cps} embed/s")
} else {
"---".to_string()
};
stats_bar.set_message(format!(
"{phase_label} {chunks} chunks \u{2014} {cps_label} \u{2014} \
Files {indexed}/{total} Skipped {skipped} Elapsed {elapsed}s ETA {eta}",
chunks = format_with_commas(chunks),
indexed = format_with_commas(indexed),
total = format_with_commas(total),
skipped = format_with_commas(skipped),
elapsed = elapsed,
eta = eta,
));
}
})
}