use std::path::Path;
use crate::notes::links::{self, Link};
use crate::notes::{Excerpt, git, has_note, note_of, write_note};
pub fn wanted(repo: &Path, named: &[&str]) -> Result<Vec<String>, String> {
if !named.is_empty() {
return named.iter().map(|c| git(repo, &["rev-parse", "--verify", &format!("{c}^{{commit}}")]).ok_or(format!("{c} is not a commit"))).collect();
}
Ok(git(repo, &["rev-list", "--max-count=200", "HEAD"]).unwrap_or_default().lines().map(str::to_string).collect())
}
fn adopt(e: &mut Excerpt, records: &[Link]) -> bool {
links::adopt(&e.commit, &e.collective, records, &mut links::Lists { fixed_by: &mut e.fixed_by, fixes: &mut e.fixes })
}
fn relink(repo: &Path, commit: &str, records: &[Link]) -> Result<bool, String> {
let Some(mut e) = note_of(repo, commit) else { return Ok(false) };
if !adopt(&mut e, records) {
return Ok(false);
}
write_note(repo, &e).map(|()| true)
}
fn link_sides(commits: &[String], records: &[Link]) -> Vec<String> {
let mut out: Vec<String> = Vec::new();
for l in records.iter().filter(|l| commits.contains(&l.commit) || commits.contains(&l.fix)) {
for c in [&l.commit, &l.fix] {
if !out.contains(c) {
out.push(c.clone());
}
}
}
out
}
fn restore_excerpts(repo: &Path, text: &str, records: &[Link], commits: &[String]) -> Result<Vec<String>, String> {
let mut done: Vec<String> = Vec::new();
for mut e in text.lines().filter_map(|l| serde_json::from_str::<Excerpt>(l).ok()) {
if e.kind != "reasoning" || !commits.contains(&e.commit) || done.contains(&e.commit) {
continue;
}
if git(repo, &["cat-file", "-e", &format!("{}^{{commit}}", e.commit)]).is_none() || has_note(repo, &e.commit) {
continue;
}
adopt(&mut e, records);
write_note(repo, &e)?;
done.push(e.commit);
}
Ok(done)
}
pub fn restore(repo: &Path, store: &Path, commits: &[String]) -> Result<Vec<String>, String> {
let text = std::fs::read_to_string(store.join("reasoning.jsonl")).unwrap_or_default();
let records = links::records(&text);
let mut done = restore_excerpts(repo, &text, &records, commits)?;
let sides: Vec<String> = link_sides(commits, &records).into_iter().filter(|c| !done.contains(c)).collect();
for c in sides {
if relink(repo, &c, &records)? {
done.push(c);
}
}
Ok(done)
}