use chrono::{DateTime, NaiveDateTime, TimeZone, Utc};
use std::path::{Path, PathBuf};
use std::time::{Duration, SystemTime};
pub const TRASHINFO_EXTENSION: &str = ".trashinfo";
pub const TRASHINFO_TIME_FORMAT: &str = "%Y-%m-%dT%H:%M:%S";
pub fn sanitize_user_path(path: &Path) -> String {
path.display().to_string().trim().to_string()
}
pub fn build_unique_basename(file_name: &str, suffix: u64) -> String {
let base = Path::new(file_name)
.file_name()
.and_then(|v| v.to_str())
.unwrap_or("item");
format!("{base}.{suffix}")
}
pub fn parse_trash_datetime(value: &str) -> Option<DateTime<Utc>> {
NaiveDateTime::parse_from_str(value, TRASHINFO_TIME_FORMAT)
.ok()
.map(|naive| Utc.from_utc_datetime(&naive))
.or_else(|| DateTime::parse_from_rfc3339(value).ok().map(|dt| dt.with_timezone(&Utc)))
}
pub fn serialize_system_time(time: SystemTime) -> String {
let dt = DateTime::<Utc>::from(time);
dt.format(TRASHINFO_TIME_FORMAT).to_string()
}
pub fn print_size(bytes: u64) -> String {
const SUFFIXES: [&str; 5] = ["B", "K", "M", "G", "T"];
let mut value = bytes as f64;
let mut idx = 0usize;
while value >= 1024.0 && idx < SUFFIXES.len() - 1 {
value /= 1024.0;
idx += 1;
}
if idx == 0 {
format!("{:.0} {}", value, SUFFIXES[idx])
} else {
format!("{:.1} {}", value, SUFFIXES[idx])
}
}
pub fn canonical_or_relaxed(path: &Path) -> PathBuf {
path.canonicalize().unwrap_or_else(|_| path.to_path_buf())
}
pub fn format_duration(duration: Duration) -> String {
let secs = duration.as_secs();
let mins = secs / 60;
let hours = mins / 60;
let days = hours / 24;
let rem_secs = secs % 60;
let rem_mins = mins % 60;
let rem_hours = hours % 24;
if days > 0 {
format!("{days}d {rem_hours:02}:{rem_mins:02}:{rem_secs:02}")
} else if hours > 0 {
format!("{hours}h {rem_mins:02}:{rem_secs:02}")
} else if mins > 0 {
format!("{mins}m {rem_secs:02}s")
} else {
format!("{secs}s")
}
}