use std::{collections::HashMap, path::PathBuf, sync::Arc};
use barber::{ProgressBar, ProgressRenderer};
use crate::{
config::common::common_config,
errors::LibraryError,
library::track::{
Track,
core_impls::{TrackRenameError, calculate_rel_path},
},
utils::clean_empty_dirs,
};
pub fn migrate(
tracks: &mut [Track],
progress_renderer: Arc<dyn ProgressRenderer>,
dry: bool,
) -> Result<(), TrackRenameError> {
let library_dir = common_config()
.library_dir()
.ok_or(LibraryError::NoLibrary)?
.to_path_buf();
let mut map = Vec::new();
let mut path_counter: HashMap<PathBuf, usize> = HashMap::new();
for track in tracks {
let Some(lib_container) = track.lib_container() else {
continue;
};
let relative_path = calculate_rel_path(&track.metadata, lib_container)?;
*path_counter.entry(relative_path.clone()).or_insert(0) += 1;
map.push((track, relative_path));
}
let duplicates: Vec<(PathBuf, usize)> =
path_counter.into_iter().filter(|(_, v)| *v > 1).collect();
if !duplicates.is_empty() {
let display_string = duplicates
.iter()
.map(|(path, count)| {
format!(
"'{path}' is duplicated {count} time(s)",
path = path.display()
)
})
.collect::<Vec<_>>()
.join("\n");
return Err(TrackRenameError::ConflictingNames(format!(
"The migration could not be completed as the following paths are conflicted:\n{display_string}"
)));
}
let progress_bar = ProgressBar::new(0, map.len(), progress_renderer);
progress_bar.set_label("Migrating files...");
for (track, path) in map {
if track.relative_library_path == path {
progress_bar.increment();
continue;
}
track.relative_library_path = path;
if !dry {
track.migrate(&library_dir)?;
}
progress_bar.increment();
}
progress_bar.flush();
clean_empty_dirs(library_dir)?;
Ok(())
}