use std::sync::Arc;
use std::time::Duration;
use rayon::prelude::*;
use crate::session_state::SessionState;
use crate::chronicle;
pub fn scavenger_loop(state: Arc<SessionState>) {
loop {
std::thread::sleep(Duration::from_secs(120));
if !state.is_scavenger_allowed() { continue; }
let workdir = state.workdir.to_string_lossy().to_string();
let db_path = state.chronicle_path.to_string_lossy().to_string();
crate::reindex::incremental_reindex(&workdir);
let entries = match std::fs::read_dir(&workdir) {
Ok(e) => e,
Err(_) => continue,
};
let file_tasks: Vec<_> = entries.flatten()
.map(|e| e.path())
.filter(|fp| {
let ext = fp.extension().and_then(|e| e.to_str()).unwrap_or("");
matches!(ext, "py" | "rs" | "js")
})
.collect();
let config = reliary_dead::DeadConfig::default();
let candidates: Vec<_> = file_tasks.par_iter().filter_map(|fp| {
let p = fp.to_str()?;
let content = std::fs::read_to_string(p).ok()?;
Some(reliary_dead::analyze_file(p, &content, &config))
}).flatten().collect();
let chronicle_db = match chronicle::init(&db_path) {
Ok(db) => db,
Err(_) => continue,
};
for c in candidates.iter() {
if c.confidence != reliary_dead::Confidence::High { continue; }
let recent = chronicle::recent_events(&chronicle_db, &c.file, 24);
if recent.iter().any(|e| e.event == "scavenge" && e.detail.contains(&c.name)) { continue; }
if let Ok(content) = std::fs::read_to_string(&c.file) {
let fixes = vec![(c.name.clone(), String::new())];
let (modified, count) = reliary_fix::apply_fixes(&content, &fixes);
if count > 0 && modified != content {
match crate::heal::heal_edit(&c.file, &modified, &workdir) {
Ok(()) => {
let _ = std::fs::write(&c.file, &modified);
chronicle::append(&chronicle_db, "scavenge", &c.file, &c.name, "removed");
eprintln!("[reliary] scavenger: removed {} from {}", c.name, c.file);
}
Err(e) => {
chronicle::append(&chronicle_db, "scavenge", &c.file, &c.name, &format!("reverted: {}", e));
}
}
}
}
}
}
}