//! Parsing utilities for systemd configuration values.

use nix::unistd::Pid;

/// Parse a boolean value using systemd's permissive parsing rules.
///
/// Accepts (case-insensitive):
/// - True: "1", "yes", "y", "true", "t", "on"
/// - False: "0", "no", "n", "false", "f", "off"
///
/// Returns `None` if the value doesn't match any known boolean representation.
pub fn parse_systemd_bool(value: &str) -> Option<bool> {
    let v = value.to_ascii_lowercase();
    match v.as_str() {
        "1" | "yes" | "y" | "true" | "t" | "on" => Some(true),
        "0" | "no" | "n" | "false" | "f" | "off" => Some(false),
        _ => None,
    }
}

/// Parse a PID value, ensuring it's valid.
///
/// systemd uses `pid_t` internally and validates that the PID is > 0.
/// Returns a `nix::unistd::Pid` on success, or an error if the value cannot
/// be parsed or is not a valid PID.
pub fn parse_pid(value: &str) -> Result<Pid, String> {
    let pid: i32 = value
        .parse()
        .map_err(|e| format!("Invalid PID '{}': {}", value, e))?;

    if pid <= 0 {
        return Err(format!("Invalid PID '{}': must be positive", pid));
    }

    Ok(Pid::from_raw(pid))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_systemd_bool_true_values() {
        // All true values (case-insensitive)
        assert_eq!(parse_systemd_bool("1"), Some(true));
        assert_eq!(parse_systemd_bool("yes"), Some(true));
        assert_eq!(parse_systemd_bool("YES"), Some(true));
        assert_eq!(parse_systemd_bool("Yes"), Some(true));
        assert_eq!(parse_systemd_bool("y"), Some(true));
        assert_eq!(parse_systemd_bool("Y"), Some(true));
        assert_eq!(parse_systemd_bool("true"), Some(true));
        assert_eq!(parse_systemd_bool("TRUE"), Some(true));
        assert_eq!(parse_systemd_bool("True"), Some(true));
        assert_eq!(parse_systemd_bool("t"), Some(true));
        assert_eq!(parse_systemd_bool("T"), Some(true));
        assert_eq!(parse_systemd_bool("on"), Some(true));
        assert_eq!(parse_systemd_bool("ON"), Some(true));
        assert_eq!(parse_systemd_bool("On"), Some(true));
    }

    #[test]
    fn test_parse_systemd_bool_false_values() {
        // All false values (case-insensitive)
        assert_eq!(parse_systemd_bool("0"), Some(false));
        assert_eq!(parse_systemd_bool("no"), Some(false));
        assert_eq!(parse_systemd_bool("NO"), Some(false));
        assert_eq!(parse_systemd_bool("No"), Some(false));
        assert_eq!(parse_systemd_bool("n"), Some(false));
        assert_eq!(parse_systemd_bool("N"), Some(false));
        assert_eq!(parse_systemd_bool("false"), Some(false));
        assert_eq!(parse_systemd_bool("FALSE"), Some(false));
        assert_eq!(parse_systemd_bool("False"), Some(false));
        assert_eq!(parse_systemd_bool("f"), Some(false));
        assert_eq!(parse_systemd_bool("F"), Some(false));
        assert_eq!(parse_systemd_bool("off"), Some(false));
        assert_eq!(parse_systemd_bool("OFF"), Some(false));
        assert_eq!(parse_systemd_bool("Off"), Some(false));
    }

    #[test]
    fn test_parse_systemd_bool_invalid_values() {
        assert_eq!(parse_systemd_bool(""), None);
        assert_eq!(parse_systemd_bool("2"), None);
        assert_eq!(parse_systemd_bool("maybe"), None);
        assert_eq!(parse_systemd_bool("yess"), None);
        assert_eq!(parse_systemd_bool("nope"), None);
        assert_eq!(parse_systemd_bool(" yes"), None); // Leading space
        assert_eq!(parse_systemd_bool("yes "), None); // Trailing space
    }

    #[test]
    fn test_parse_pid_valid() {
        assert_eq!(parse_pid("1"), Ok(Pid::from_raw(1)));
        assert_eq!(parse_pid("473501"), Ok(Pid::from_raw(473501)));
        assert_eq!(parse_pid("32767"), Ok(Pid::from_raw(32767))); // Typical max PID on 32-bit
    }

    #[test]
    fn test_parse_pid_invalid() {
        assert!(parse_pid("0").is_err()); // Zero is invalid
        assert!(parse_pid("-1").is_err()); // Negative is invalid
        assert!(parse_pid("-100").is_err());
        assert!(parse_pid("").is_err()); // Empty
        assert!(parse_pid("abc").is_err()); // Non-numeric
        assert!(parse_pid("12.5").is_err()); // Float
        assert!(parse_pid("12abc").is_err()); // Mixed
    }
}
