use crate::api::change::Change;
use crate::api::notifications::{Inbox, InboxFilter, ThreadAt};
use super::Plan;
use crate::keymap::Action;
pub(super) fn plan(
query: &str,
inbox: &Inbox,
loaded: Option<u64>,
action: Action,
) -> Result<Plan, String> {
let filter = InboxFilter::parse(query);
let rows = &inbox.list.items;
let more = inbox.list.next.is_some();
let threads = |n: usize| match n {
1 => "1 notification".to_owned(),
n => format!("{n} notifications"),
};
let mut facts = Vec::new();
let (title, label, change) = if action == Action::MarkAllRead {
let unread: Vec<ThreadAt> = (rows.iter().filter(|n| n.unread))
.map(ThreadAt::of)
.collect();
if unread.is_empty() {
return Err("Nothing shown is unread".into());
}
let title = format!("Mark {} read?", threads(unread.len()));
let whole = filter.reasons.is_empty() && !filter.participating;
let newest = rows.iter().map(|n| n.updated_at.clone()).max();
let upto = loaded.map(crate::ui::time::iso8601).or(newest);
let change = match upto {
Some(upto) if whole => {
if more {
let older = "And the older ones further down, not loaded yet";
facts.push((older.to_owned(), false));
}
Change::MarkAllRead {
repo: filter.repo,
last_read_at: upto,
}
}
_ => {
if more {
facts.push((loaded_only(rows.len()), false));
}
Change::MarkEach {
threads: unread,
done: false,
}
}
};
(title, "Mark read", change)
} else {
if rows.is_empty() {
return Err("Nothing is shown".into());
}
facts.push(("Done takes them out of your inbox".to_owned(), false));
if more {
facts.push((loaded_only(rows.len()), false));
}
let change = Change::MarkEach {
threads: rows.iter().map(ThreadAt::of).collect(),
done: true,
};
(
format!("Mark {} done?", threads(rows.len())),
"Mark done",
change,
)
};
Ok(Plan::Ask(title, facts, vec![(label.to_owned(), change)]))
}
fn loaded_only(n: usize) -> String {
format!("Only the {n} loaded: those further down stay as they are")
}
pub(super) fn shows(inbox: &Inbox, change: &Change) -> bool {
let rows = &inbox.list.items;
match change {
Change::MarkAllRead { last_read_at, .. } => rows
.iter()
.all(|n| !n.unread || n.updated_at.as_str() > last_read_at.as_str()),
Change::MarkEach { threads, done } => {
let marked = |id: &str| threads.iter().any(|t| t.id == id);
let mut about = rows.iter().filter(|n| marked(&n.id));
if *done {
about.next().is_none()
} else {
about.all(|n| !n.unread)
}
}
_ => true,
}
}