use crate::config::Config;
use chrono::{Duration, NaiveTime};
pub fn month_name(month: &str) -> &'static str {
match month {
"01" => "January",
"02" => "February",
"03" => "March",
"04" => "April",
"05" => "May",
"06" => "June",
"07" => "July",
"08" => "August",
"09" => "September",
"10" => "October",
"11" => "November",
"12" => "December",
_ => "Unknown",
}
}
pub fn calculate_expected_exit(start: &str, work_minutes: i64, lunch: i32) -> NaiveTime {
let start_time = NaiveTime::parse_from_str(start, "%H:%M").expect("Invalid start time format");
let work_duration = Duration::minutes(work_minutes);
let lunch_clamped = lunch.clamp(30, 90);
let base_lunch = Duration::minutes(30);
let extra = Duration::minutes((lunch_clamped - 30) as i64);
start_time + work_duration + base_lunch + extra
}
pub fn calculate_surplus(start: &str, lunch: i32, end: &str, work_minutes: i64) -> Duration {
let expected = calculate_expected_exit(start, work_minutes, lunch);
let actual = NaiveTime::parse_from_str(end, "%H:%M").expect("Invalid end time format");
actual - expected
}
pub fn crosses_lunch_window(start: &str, end: &str) -> bool {
let start_time = match NaiveTime::parse_from_str(start, "%H:%M") {
Ok(t) => t,
Err(_) => return false,
};
let end_time = match NaiveTime::parse_from_str(end, "%H:%M") {
Ok(t) => t,
Err(_) => return false,
};
let lunch_start = NaiveTime::parse_from_str("12:30", "%H:%M").unwrap();
let lunch_end = NaiveTime::parse_from_str("14:30", "%H:%M").unwrap();
start_time < lunch_end && end_time > lunch_start
}
pub fn effective_lunch_minutes(
lunch: i32,
start: &str,
end: &str,
position: char,
config: &Config,
) -> i32 {
let crosses = crosses_lunch_window(start, end);
match position {
'O' => {
if crosses {
let l = lunch.clamp(
config.min_duration_lunch_break,
config.max_duration_lunch_break,
);
if l < 30 { 30 } else { l }
} else {
0
}
}
'H' => 0,
_ => lunch.clamp(0, 90),
}
}