use crate::scanner::FsNode;
use serde::Serialize;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize)]
pub struct SizeEntry {
pub path: PathBuf,
pub size: u64,
pub is_dir: bool,
}
pub fn top_files(root: &FsNode, min_size: u64, limit: usize) -> Vec<SizeEntry> {
let mut files = Vec::new();
root.flatten_files(&mut files);
let mut entries: Vec<SizeEntry> = files.into_iter()
.filter(|f| f.size >= min_size)
.map(|f| SizeEntry { path: f.path.clone(), size: f.size, is_dir: false })
.collect();
entries.sort_by(|a, b| b.size.cmp(&a.size));
entries.truncate(limit);
entries
}
pub fn top_dirs(root: &FsNode, limit: usize) -> Vec<SizeEntry> {
let mut out = Vec::new();
collect_dirs(root, &mut out);
out.sort_by(|a, b| b.size.cmp(&a.size));
out.truncate(limit);
out
}
fn collect_dirs(node: &FsNode, out: &mut Vec<SizeEntry>) {
if !node.is_dir { return; }
out.push(SizeEntry { path: node.path.clone(), size: node.size, is_dir: true });
for c in &node.children {
if c.is_dir { collect_dirs(c, out); }
}
}
pub fn type_breakdown(root: &FsNode) -> Vec<(String, u64, u64)> {
let mut files = Vec::new();
root.flatten_files(&mut files);
use std::collections::HashMap;
let mut groups: HashMap<&'static str, (u64, u64)> = HashMap::new();
for f in files {
let ext = f.path.extension().and_then(|e| e.to_str()).unwrap_or("").to_lowercase();
let cat = categorize_ext(&ext);
let entry = groups.entry(cat).or_insert((0, 0));
entry.0 += f.size;
entry.1 += 1;
}
let mut result: Vec<(String, u64, u64)> = groups.into_iter().map(|(k, (s, c))| (k.to_string(), s, c)).collect();
result.sort_by(|a, b| b.1.cmp(&a.1));
result
}
fn categorize_ext(ext: &str) -> &'static str {
match ext {
"mp4" | "mkv" | "avi" | "mov" | "webm" | "flv" => "video",
"jpg" | "jpeg" | "png" | "gif" | "webp" | "bmp" | "svg" | "raw" => "image",
"mp3" | "wav" | "flac" | "ogg" | "m4a" => "audio",
"zip" | "tar" | "gz" | "xz" | "7z" | "rar" | "bz2" | "zst" => "archive",
"iso" | "img" | "appimage" | "deb" | "rpm" => "package",
"pdf" | "doc" | "docx" | "xls" | "xlsx" | "ppt" | "pptx" | "odt" => "document",
"log" => "log",
"so" | "dll" | "bin" | "exe" | "o" | "a" => "binary",
"" => "no-extension",
_ => "other",
}
}