use std::error::Error;
use std::fmt;
use std::time::Duration;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DurationParseError {
    message: String,
}

impl DurationParseError {
    fn new(error: humantime::DurationError) -> Self {
        Self {
            message: error.to_string(),
        }
    }
}

impl fmt::Display for DurationParseError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "expected humantime duration like 250ms, 2s, 5m, 1h, or 1d ({})",
            self.message
        )
    }
}

impl Error for DurationParseError {}

pub fn parse_duration(value: &str) -> Result<Duration, DurationParseError> {
    humantime::parse_duration(value.trim()).map_err(DurationParseError::new)
}

pub fn format_duration(value: Duration) -> String {
    humantime::format_duration(value).to_string()
}

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

    #[test]
    fn parses_seconds() {
        assert_eq!(
            parse_duration("2s").expect("duration parses"),
            Duration::from_secs(2)
        );
    }

    #[test]
    fn rejects_missing_unit() {
        assert!(parse_duration("2").is_err());
    }

    #[test]
    fn formats_exact_unit() {
        assert_eq!(format_duration(Duration::from_millis(250)), "250ms");
    }
}
