use eyre::Result;
use log::error;

pub struct Device {
    sysname: String,
    output: String,
}

impl Device {
    pub fn sysname(&self) -> &str {
        self.sysname.as_str()
    }

    pub fn properties(&self) -> impl Iterator<Item = (&str, &str)> {
        self.output
            .lines()
            .filter_map(|line| line.strip_prefix("E: ")?.split_once('='))
    }
}

pub fn get_devices(class: &str) -> Result<Vec<Device>> {
    let mut devices = Vec::new();

    // none of libudev and udev crates were able to list network devices.
    // falling back to manual sysfs scanning :(
    //
    // Even when given a syspath,
    // - udev crate failed to see all properties;
    // - libudev crate segfaulted on the second property (SYSNUM ok, then segfault).
    // falling back to parsing udevadm output :(
    //
    // The best fix would be to check what's wrong with udev crate.

    let entries = std::fs::read_dir(format!("/sys/class/{class}"))?;
    for entry in entries {
        let Ok(entry) = entry else {
            continue;
        };

        let path = entry.path();
        let path = path.to_string_lossy();

        let output = std::process::Command::new("udevadm")
            .args(&["info", &format!("--path={path}")])
            .stderr(std::process::Stdio::piped())
            .output()?;

        if !output.status.success() {
            error!("udevadm fail for {path}");
            continue;
        }

        let output = String::from_utf8_lossy(&output.stdout);

        let name = entry.file_name();
        let dev = Device {
            sysname: name.to_string_lossy().to_string(),
            output: output.into_owned(),
        };

        devices.push(dev);
    }

    Ok(devices)
}