use std::{
    collections::BTreeMap,
    fs::{read_dir, File},
    hash::Hasher,
    io::Read,
    path::{Path, PathBuf},
};

type Duplicates = BTreeMap<(u64, u64), Vec<PathBuf>>;

struct DuplicateFinder {
    found: Duplicates,
    min_size: u64,
}

impl DuplicateFinder {
    fn search(path: impl AsRef<Path>, min_size: u64) -> std::io::Result<Duplicates> {
        let mut result = Self {
            found: BTreeMap::new(),
            min_size,
        };

        result.walk(path)?;
        Ok(result.found)
    }

    fn walk(&mut self, path: impl AsRef<Path>) -> std::io::Result<()> {
        let listing = read_dir(path.as_ref())?;
        for entry in listing {
            let entry = entry?;
            let path = entry.path();
            if path.is_dir() {
                self.walk(path)?;
            } else {
                self.compute_digest(&path)?;
            }
        }

        Ok(())
    }

    fn compute_digest(&mut self, file: &Path) -> std::io::Result<()> {
        let size = file.metadata()?.len();
        if size < self.min_size {
            return Ok(());
        }