use std::path::PathBuf;

use sysinfo::Pid;

#[derive(Clone, Debug)]
pub enum Target {
    Pid(Pid),
    Port(u16),
    Name(String),
    Directory(PathBuf),
}

pub fn parse_targets(input: &[String]) -> Vec<Target> {
    input.iter().map(|item| parse_target(item)).collect()
}

fn parse_target(input: &str) -> Target {
    if let Some(port) = input
        .strip_prefix(':')
        .and_then(|value| value.parse::<u16>().ok())
    {
        return Target::Port(port);
    }

    if let Ok(pid) = input.parse::<u32>() {
        return Target::Pid(Pid::from_u32(pid));
    }

    Target::Name(input.to_string())
}

#[cfg(test)]
mod tests {
    use sysinfo::Pid;

    use super::{Target, parse_targets};

    #[test]
    fn parses_mixed_targets() {
        let parsed = parse_targets(&["1234".to_string(), ":3000".to_string(), "node".to_string()]);

        assert!(matches!(parsed[0], Target::Pid(pid) if pid == Pid::from_u32(1234)));
        assert!(matches!(parsed[1], Target::Port(3000)));
        assert!(matches!(parsed[2], Target::Name(ref name) if name == "node"));
    }

    #[test]
    fn keeps_invalid_port_like_input_as_name() {
        let parsed = parse_targets(&[":abc".to_string()]);
        assert!(matches!(parsed[0], Target::Name(ref name) if name == ":abc"));
    }
}
