use std::path::Path;
use std::path::PathBuf;

use crate::cli::ArchiveType;
use crate::cli::FormatFileExt;


pub async fn validate_and_unglob(mut paths: Vec<PathBuf>) -> Result<Vec<PathBuf>, Box<dyn std::error::Error>> {
	let unexisting = paths.drain_filter(|p| !p.try_exists().ok().unwrap_or(false));
	let mut resolved = Vec::new();
	for query in unexisting {
		let current = resolved.len();
		resolved.extend(unglob(query.to_string_lossy()).await?);

		if current == resolved.len() {
			warn!("Path or glob pattern '{}' is wrong and will be ignored", query.display());
		}
	}
	paths.append(&mut resolved);

	// Need dedup but not sort because we want to keep the order, user's preferred order...
	// Or not? Ok, just sort & dedup:
	paths.sort();
	paths.dedup();

	Ok(paths)
}

pub async fn unglob<S: AsRef<str>>(pattern: S) -> Result<impl Iterator<Item = PathBuf>, Box<dyn std::error::Error>> {
	use glob::glob;
	Ok(glob(pattern.as_ref())?.filter_map(|res| res.map_err(|err| error!("{err}")).ok()))
}


/// Prepare source path to concat with dst path.
fn sanitize_path(path: &Path) -> PathBuf {
	if path.is_absolute() {
		path.components().skip(1).collect()
	} else {
		path.components()
		    .filter(|c| !matches!(c, std::path::Component::ParentDir))
		    .collect()
	}
}


pub fn output_archive_path(source: impl AsRef<Path>, outdir: impl AsRef<Path>, archive: ArchiveType) -> PathBuf {
	let source = source.as_ref();
	let subpath = if source.is_absolute() {
		source.file_name()
		      .map(Path::new)
		      .or(source.parent())
		      .expect("invalid path")
		      .with_extension(archive.ext())
	} else {
		sanitize_path(source).with_extension(archive.ext())
	};

	let output = outdir.as_ref().join(subpath);
	output
}
