use super::ShellState;
use crate::AppModel;
use crate::actions::DraftKey;
use crate::boundary::Action;
use crate::wire::post::Ticket;
use std::path::{Path, PathBuf};
pub(super) mod start;
enum Owes {
Nothing,
Message { agent: String, content: String },
Prepared { goal: Option<String> },
Started { goal: String },
}
#[derive(Clone)]
enum Seat {
Quiet,
Draft(DraftKey),
Line(DraftKey),
}
pub(super) struct Acting {
ticket: Ticket,
ws: PathBuf,
seat: Seat,
owes: Owes,
}
pub(super) fn message(
model: &mut AppModel,
state: &mut ShellState,
key: &DraftKey,
ws: &Path,
agent: &str,
content: &str,
) {
let action = Action::Message {
workspace: model.snap.ws_name(ws),
agent: agent.to_owned(),
content: content.to_owned(),
};
hold(
model,
state,
ws,
&action,
Seat::Draft(key.clone()),
Owes::Message {
agent: agent.to_owned(),
content: content.to_owned(),
},
);
}
pub(super) fn line(
model: &mut AppModel,
state: &mut ShellState,
key: &DraftKey,
ws: &Path,
action: &Action,
) {
let owes = match action {
Action::Prepare { .. } => Owes::Prepared { goal: None },
Action::Prompt { goal, .. } => Owes::Started { goal: goal.clone() },
_ => Owes::Nothing,
};
hold(model, state, ws, action, Seat::Line(key.clone()), owes);
}
fn hold(
model: &mut AppModel,
state: &mut ShellState,
ws: &Path,
action: &Action,
seat: Seat,
owes: Owes,
) {
let ticket = model.post_act(action);
state.acting = Some(Acting {
ticket,
ws: ws.to_path_buf(),
seat,
owes,
});
}
pub(super) fn settle(model: &mut AppModel, state: &mut ShellState) {
let Some(ticket) = state.acting.as_ref().map(|a| a.ticket) else {
return;
};
let Some(landed) = model.act_receipt(ticket) else {
return;
};
let Some(acting) = state.acting.take() else {
return;
};
let trouble = super::act::trouble(&landed);
if trouble.is_none() && acted(model, state, &acting, &landed) {
return;
}
match acting.seat {
Seat::Quiet => quietly(state, trouble),
Seat::Draft(key) => match trouble {
None => state.actions.drafts.set(key, String::new()),
Some(reason) => state.slash = Some(reason),
},
Seat::Line(key) => {
if super::slash::note(state, landed) {
state.actions.drafts.set(key, String::new());
}
}
}
}
fn acted(
model: &mut AppModel,
state: &mut ShellState,
acting: &Acting,
landed: &Result<crate::boundary::reply::Reply, String>,
) -> bool {
use crate::boundary::reply::Reply;
match (&acting.owes, landed) {
(Owes::Message { agent, content }, _) => {
model.await_message(&acting.ws, agent, content);
false
}
(Owes::Prepared { goal }, Ok(Reply::Prepared(prepared))) => {
start::staged(model, state, acting, prepared, goal.clone())
}
(Owes::Started { goal }, Ok(Reply::Started { conversation })) => {
start::fired(model, state, &acting.ws, conversation, goal);
false
}
(_, _) => false,
}
}
fn quietly(state: &mut ShellState, trouble: Option<String>) {
if let Some(reason) = trouble {
state.slash = Some(reason);
}
}