yoo 0.6.2

A tiny developer companion for better coding sessions.
use std::{
    io::{self, Write},
    thread,
    time::{Duration, Instant},
};

pub const MIN_MINUTES: u64 = 1;
pub const MAX_MINUTES: u64 = 480;

pub fn validate_minutes(minutes: u64) -> Result<(), String> {
    if !(MIN_MINUTES..=MAX_MINUTES).contains(&minutes) {
        return Err(format!(
            "minutes must be between {MIN_MINUTES} and {MAX_MINUTES}"
        ));
    }

    Ok(())
}

pub fn start(minutes: u64, show_complete_message: bool) -> io::Result<()> {
    validate_minutes(minutes)
        .map_err(|message| io::Error::new(io::ErrorKind::InvalidInput, message))?;

    let total_seconds = minutes * 60;
    println!("🍅 Local coding session started for {minutes} minute(s). Press Ctrl+C to stop it.");

    let start = Instant::now();
    loop {
        let elapsed = start.elapsed().as_secs();
        if elapsed >= total_seconds {
            break;
        }

        let remaining = total_seconds - elapsed;
        print!("\r⏳ Session remaining: {} ", format_duration(remaining));
        io::stdout().flush()?;
        thread::sleep(Duration::from_millis(250));
    }

    println!("\r✅ Session complete.                    ");
    if show_complete_message {
        println!("Stretch, drink water, and commit something you are proud of. 🚀");
    }

    Ok(())
}

pub fn format_duration(total_seconds: u64) -> String {
    let minutes = total_seconds / 60;
    let seconds = total_seconds % 60;
    format!("{minutes:02}:{seconds:02}")
}

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

    #[test]
    fn formats_a_duration() {
        assert_eq!(format_duration(65), "01:05");
        assert_eq!(format_duration(3_600), "60:00");
    }

    #[test]
    fn rejects_invalid_minutes() {
        assert!(validate_minutes(0).is_err());
        assert!(validate_minutes(481).is_err());
        assert!(validate_minutes(25).is_ok());
    }
}