use axum::http::StatusCode;
use std::net::IpAddr;

const MAX_IDENTIFIER_LEN: usize = 128;

pub fn validate_identifier(value: &str, label: &str) -> Result<(), (StatusCode, String)> {
    let trimmed = value.trim();
    if trimmed.is_empty() {
        return Err((StatusCode::BAD_REQUEST, format!("{} is required", label)));
    }

    if trimmed.len() > MAX_IDENTIFIER_LEN {
        return Err((StatusCode::BAD_REQUEST, format!("{} is too long", label)));
    }

    if !trimmed
        .chars()
        .all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.'))
    {
        return Err((
            StatusCode::BAD_REQUEST,
            format!("{} contains invalid characters", label),
        ));
    }

    Ok(())
}

pub fn validate_ip(value: &str, label: &str) -> Result<(), (StatusCode, String)> {
    let trimmed = value.trim();
    if trimmed.is_empty() {
        return Err((StatusCode::BAD_REQUEST, format!("{} is required", label)));
    }

    if trimmed.parse::<IpAddr>().is_err() {
        return Err((
            StatusCode::BAD_REQUEST,
            format!("{} must be a valid IP address", label),
        ));
    }

    Ok(())
}

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

    #[test]
    fn validate_ip_accepts_ipv4() {
        assert!(validate_ip("10.0.1.10", "ip").is_ok());
    }

    #[test]
    fn validate_ip_accepts_ipv6() {
        assert!(validate_ip("2001:db8::1", "ip").is_ok());
    }

    #[test]
    fn validate_ip_rejects_invalid() {
        assert!(validate_ip("not-an-ip", "ip").is_err());
    }
}
