use std::time::Duration;

#[derive(Debug)]
pub enum ParseDurationError {
    InvalidFormat,
    UnknownUnit(String),
}

pub fn parse_duration(input: &str) -> Result<Duration, ParseDurationError> {
    let mut total = 0.0f64; // Formatted to Float64

    for part in input.split_whitespace() {
        let idx = part
            .find(|c: char| c.is_ascii_alphabetic())
            .ok_or(ParseDurationError::InvalidFormat)?;

        let (num, unit) = part.split_at(idx);

        let value: f64 = num
            .parse()
            .map_err(|_| ParseDurationError::InvalidFormat)?;

        let seconds = match unit {
            "ms" => value / 1000.0,                     // Milliseconds
            "s" | "sec" | "secs" => value,              // Seconds
            "m" | "min" | "mins" => value * 60.0,       // Minutes
            "h" | "hr" | "hrs" => value * 3600.0,       // Hours
            "d" | "day" | "days" => value * 86400.0,    // Day
            other => {
                return Err(ParseDurationError::UnknownUnit(other.to_string()));
            }
        };

        total += seconds;
    }

    Ok(Duration::from_secs_f64(total))
}

pub fn human_duration(duration: Duration) -> String {
    let mut secs = duration.as_secs();

    let days = secs / 86400;
    secs %= 86400;

    let hours = secs / 3600;
    secs %= 3600;

    let mins = secs / 60;
    secs %= 60;

    let mut parts = Vec::new();

    if days > 0 {
        parts.push(format!("{days}d"));
    }

    if hours > 0 {
        parts.push(format!("{hours}h"));
    }

    if mins > 0 {
        parts.push(format!("{mins}m"));
    }

    if secs > 0 || parts.is_empty() {
        parts.push(format!("{secs}s"));
    }

    parts.join(" ")
}

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

    #[test]
    fn parse_simple() {
        assert_eq!(
            parse_duration("5s").unwrap(),
            Duration::from_secs(5)
        );
    }

    #[test]
    fn parse_complex() {
        assert_eq!(
            parse_duration("1h 30m").unwrap(),
            Duration::from_secs(5400)
        );
    }

    #[test]
    fn format_duration() {
        assert_eq!(
            human_duration(Duration::from_secs(7265)),
            "2h 1m 5s"
        );
    }
}