use chrono::{Datelike, Duration, Local, NaiveDate, NaiveDateTime};
use crate::app::{at_work_span_of, App};
use crate::models::TimeEntry;
pub struct DaySummary {
pub date: NaiveDate,
pub span: Option<(NaiveDateTime, NaiveDateTime, bool)>,
pub logged_min: i64,
pub unlogged_min: i64,
pub workday_min: i64,
pub missing_lunch: bool,
pub entries: Vec<TimeEntry>,
}
pub fn week_start_of(date: NaiveDate) -> NaiveDate {
let days_from_monday = date.weekday().num_days_from_monday() as i64;
date - Duration::days(days_from_monday)
}
pub fn build_week(app: &App, anchor: NaiveDate) -> Vec<DaySummary> {
let now = Local::now().naive_local();
let monday = week_start_of(anchor);
(0..7)
.map(|i| {
let date = monday + Duration::days(i);
let entries = app.db.get_entries_for_date(date).unwrap_or_default();
let (start_ov, end_ov) = app.db.get_day_overrides(date).unwrap_or((None, None));
let span = at_work_span_of(&entries, start_ov, end_ov, now);
let mut logged_min = 0i64;
let mut unlogged_min = 0i64;
let mut off_work_min = 0i64;
let mut has_work = false;
let mut has_off_work = false;
for e in &entries {
let minutes = e
.end_time
.unwrap_or(now)
.signed_duration_since(e.start_time)
.num_minutes()
.max(0);
if e.off_work {
off_work_min += minutes;
has_off_work = true;
} else {
has_work = true;
if e.logged {
logged_min += minutes;
} else {
unlogged_min += minutes;
}
}
}
let span_min = span
.map(|(s, en, _)| en.signed_duration_since(s).num_minutes().max(0))
.unwrap_or(0);
let workday_min = (span_min - off_work_min).max(0);
DaySummary {
date,
span,
logged_min,
unlogged_min,
workday_min,
missing_lunch: has_work && !has_off_work,
entries,
}
})
.collect()
}