use anyhow::{Result, anyhow};
use colored::Colorize;
use futures::future::join_all;
use pidge_client::{AuthClient, ClientError, GraphClient};
use pidge_core::{Config, Message, MessageCache, short_hash};
use crate::commands::mail::{MessageRow, account_labels, render};
pub async fn run(
query: String,
account_filter: Vec<String>,
limit: usize,
compact: bool,
table: bool,
full: bool,
json: bool,
) -> Result<()> {
let config = Config::load()?;
if config.accounts.is_empty() {
return Err(anyhow!(
"No accounts signed in. Run `pidge account add` to add one."
));
}
let target_emails: Vec<String> = if account_filter.is_empty() {
config.accounts.iter().map(|a| a.email.clone()).collect()
} else {
for f in &account_filter {
if config.find(f).is_none() {
return Err(anyhow!("not signed in to {f}"));
}
}
account_filter
};
let graph = GraphClient::new(AuthClient::from_env()?)?;
let futures = target_emails.iter().map(|email| {
let graph = &graph;
let e = email.clone();
let q = query.clone();
async move {
let result = graph.search_messages(&e, &q, limit).await;
(e, result)
}
});
let mut had_success = false;
let mut messages: Vec<Message> = Vec::new();
for (email, result) in join_all(futures).await {
match result {
Ok(msgs) => {
had_success = true;
messages.extend(msgs);
}
Err(ClientError::SessionExpired { email: e }) => {
eprintln!(
"{} {e}: session expired, run `pidge account add`",
"WARNING:".yellow().bold()
);
}
Err(e) => eprintln!("{} {email}: {e}", "WARNING:".yellow().bold()),
}
}
if !had_success {
return Err(anyhow!("All searched accounts failed."));
}
messages.truncate(limit);
{
let mut cache = MessageCache::load()?;
let pairs: Vec<(String, String)> = messages
.iter()
.map(|m| (m.id.clone(), m.account.clone()))
.collect();
cache.insert_many(&pairs);
cache.save()?;
}
if messages.is_empty() && !json {
println!("No matches.");
return Ok(());
}
let rows: Vec<MessageRow> = messages
.into_iter()
.map(|m| {
let h = short_hash(&m.id);
MessageRow {
message: m,
short_hash: h,
}
})
.collect();
let single_account = target_emails.len() == 1;
let labels = account_labels(&target_emails);
render(&rows, single_account, &labels, compact, table, full, json)
}