use crate::config::Config;
use crate::elements::{Element, ElementKind};
use crate::store::Store;
use anyhow::Result;
use chrono::NaiveDate;
use colored::Colorize;
pub fn run(config: &Config, dates: Vec<NaiveDate>, all: bool) -> Result<()> {
let store = Store::new(&config.storage_dir);
let effective_dates: Vec<NaiveDate> = if all { store.all_file_dates()? } else { dates };
let multi = effective_dates.len() > 1;
let mut grand_tasks = 0usize;
let mut grand_notes = 0usize;
let mut grand_reminders = 0usize;
let mut grand_logs = 0usize;
let mut grand_log_mins = 0i64;
let mut grand_characters = 0usize;
let mut any = false;
for d in &effective_dates {
let elements: Vec<Element> = store
.parse_date(*d)?
.into_values()
.filter(|e| !e.is_mps_group() && !e.is_unknown())
.collect();
if elements.is_empty() {
continue;
}
any = true;
let tasks: Vec<&Element> = elements
.iter()
.filter(|e| e.kind() == ElementKind::Task)
.collect();
let notes: usize = elements
.iter()
.filter(|e| e.kind() == ElementKind::Note)
.count();
let reminders: usize = elements
.iter()
.filter(|e| e.kind() == ElementKind::Reminder)
.count();
let logs: Vec<&Element> = elements
.iter()
.filter(|e| e.kind() == ElementKind::Log)
.collect();
let characters: usize = elements
.iter()
.filter(|e| e.kind() == ElementKind::Character)
.count();
let open_n = tasks
.iter()
.filter(|e| {
if let Element::Task { data, .. } = e {
data.is_open()
} else {
false
}
})
.count();
let done_n = tasks.len() - open_n;
let log_mins: i64 = logs
.iter()
.map(|e| {
if let Element::Log { data, .. } = e {
data.duration_minutes().unwrap_or(0)
} else {
0
}
})
.sum();
grand_tasks += tasks.len();
grand_notes += notes;
grand_reminders += reminders;
grand_logs += logs.len();
grand_log_mins += log_mins;
grand_characters += characters;
let mut parts: Vec<String> = Vec::new();
if !tasks.is_empty() {
let n = tasks.len();
parts.push(format!(
"{} task{} ({}, {})",
n,
if n != 1 { "s" } else { "" },
format!("{} open", open_n).yellow(),
format!("{} done", done_n).green()
));
}
if notes > 0 {
parts.push(format!(
"{} note{}",
notes,
if notes != 1 { "s" } else { "" }
));
}
if reminders > 0 {
parts.push(format!(
"{} reminder{}",
reminders,
if reminders != 1 { "s" } else { "" }
));
}
if !logs.is_empty() {
let n = logs.len();
let dur = format_duration(log_mins);
let dur_suffix = if dur.is_empty() {
String::new()
} else {
format!(" ({})", dur)
};
parts.push(format!(
"{} log{}{}",
n,
if n != 1 { "s" } else { "" },
dur_suffix
));
}
if characters > 0 {
parts.push(format!(
"{} character{}",
characters,
if characters != 1 { "s" } else { "" }
));
}
println!(
"{} — {}",
d.format("%Y-%m-%d").to_string().white(),
parts.join(", ")
);
}
if !any {
println!("{}", "(no data found)".yellow());
return Ok(());
}
if multi && any {
println!("{}", "─".repeat(44).white());
let mut tparts: Vec<String> = Vec::new();
if grand_tasks > 0 {
tparts.push(format!("{} tasks", grand_tasks));
}
if grand_notes > 0 {
tparts.push(format!("{} notes", grand_notes));
}
if grand_reminders > 0 {
tparts.push(format!("{} reminders", grand_reminders));
}
if grand_logs > 0 {
let dur = format_duration(grand_log_mins);
let dur_suffix = if dur.is_empty() {
String::new()
} else {
format!(" ({} total)", dur)
};
tparts.push(format!("{} logs{}", grand_logs, dur_suffix));
}
if grand_characters > 0 {
tparts.push(format!("{} characters", grand_characters));
}
println!("Total: {}", tparts.join(", "));
}
Ok(())
}
fn format_duration(mins: i64) -> String {
if mins <= 0 {
return String::new();
}
let h = mins / 60;
let m = mins % 60;
if m > 0 {
format!("{}h{}m", h, m)
} else {
format!("{}h", h)
}
}