use crate::libs::formatter::format_duration;
use chrono::{Duration, NaiveDate};
use std::collections::{HashMap, HashSet};
#[derive(Debug, Clone)]
pub struct DailySummary {
pub date: NaiveDate,
pub duration: Duration,
pub productivity: f64,
}
pub trait SummaryCalculator {
fn add_rest_dates(self, rest_dates: HashSet<NaiveDate>, duration: Duration) -> Self;
fn calculate_totals(self) -> (Self, Duration, Duration)
where
Self: Sized;
}
impl SummaryCalculator for Vec<DailySummary> {
fn add_rest_dates(mut self, rest_dates: HashSet<NaiveDate>, duration: Duration) -> Self {
for rest_date in rest_dates {
let date_exists = self.iter().any(|summary| summary.date == rest_date);
if !date_exists {
self.push(DailySummary {
date: rest_date,
duration,
productivity: 0.0, });
}
}
self
}
fn calculate_totals(mut self) -> (Self, Duration, Duration) {
self.sort_by_key(|summary| summary.date);
let total_duration = self.iter().fold(Duration::zero(), |accumulator, summary| accumulator + summary.duration);
let day_count = self.len() as i64;
let average_duration = if day_count > 0 {
Duration::seconds(total_duration.num_seconds() / day_count)
} else {
Duration::zero()
};
(self, total_duration, average_duration)
}
}
pub trait SummaryFormatter {
fn format_summary(&self) -> (HashMap<NaiveDate, (String, String)>, String, String);
}
impl SummaryFormatter for (Vec<DailySummary>, Duration, Duration) {
fn format_summary(&self) -> (HashMap<NaiveDate, (String, String)>, String, String) {
let (daily_summaries, total_duration, average_duration) = self;
let daily_durations = daily_summaries
.iter()
.map(|summary| {
let formatted_duration = format_duration(&summary.duration);
let formatted_productivity = format!("{:.1}%", summary.productivity);
(summary.date, (formatted_duration, formatted_productivity))
})
.collect();
let total_duration_str = format_duration(total_duration);
let average_duration_str = format_duration(average_duration);
(daily_durations, total_duration_str, average_duration_str)
}
}