use std::path::PathBuf;
use anyhow::Result;
use atm_core::address::AgentAddress;
use atm_core::home;
use atm_core::send::{self, SendMessageSource, SendRequest};
use atm_core::types::{AgentName, TeamName};
use clap::Args;
use crate::observability::CliObservability;
use crate::output;
#[derive(Debug, Args)]
#[command(
after_help = "Post-send hooks can be configured in .atm.toml via [atm].post_send_hook plus [atm].post_send_hook_senders and/or [atm].post_send_hook_recipients. Omitted or empty sender/recipient lists do not match; if both lists are omitted or empty, the hook stays disabled. Use '*' in either list to match all senders or recipients. For hook troubleshooting, combine --stderr-logs with ATM_LOG=debug to surface debug-level hook diagnostics on stderr."
)]
pub struct SendCommand {
#[arg()]
to: String,
#[arg(index = 2)]
message: Option<String>,
#[arg(long)]
from: Option<String>,
#[arg(long)]
team: Option<String>,
#[arg(long)]
file: Option<PathBuf>,
#[arg(long)]
stdin: bool,
#[arg(long)]
summary: Option<String>,
#[arg(long = "requires-ack")]
requires_ack: bool,
#[arg(long = "task-id")]
task_id: Option<String>,
#[arg(long)]
dry_run: bool,
#[arg(long)]
json: bool,
}
impl SendCommand {
pub fn run(self, observability: &CliObservability) -> Result<()> {
let current_dir = std::env::current_dir()?;
let home_dir = home::atm_home()?;
let message_source = self.build_message_source()?;
let to: AgentAddress = self.to.parse()?;
let outcome = send::send_mail(
SendRequest {
home_dir,
current_dir,
sender_override: self.from.map(AgentName::from),
to,
team_override: self.team.map(TeamName::from),
message_source,
summary_override: self.summary,
requires_ack: self.requires_ack,
task_id: self.task_id,
dry_run: self.dry_run,
},
observability,
)?;
output::print_send_result(&outcome, self.json)
}
fn build_message_source(&self) -> Result<SendMessageSource> {
if self.stdin && self.file.is_some() {
anyhow::bail!("--stdin and --file are mutually exclusive");
}
if self.stdin && self.message.is_some() {
anyhow::bail!("--stdin and positional message text are mutually exclusive");
}
match (&self.file, self.stdin, &self.message) {
(Some(path), false, message) => Ok(SendMessageSource::File {
path: path.clone(),
message: message.clone(),
}),
(None, true, None) => Ok(SendMessageSource::Stdin),
(None, false, Some(message)) => Ok(SendMessageSource::Inline(message.clone())),
(None, false, None) => {
anyhow::bail!("provide message text, --file, or --stdin")
}
(Some(_), true, _) => unreachable!("validated above"),
(None, true, Some(_)) => unreachable!("validated above"),
}
}
}