use std::io::Write;
use std::path::PathBuf;
use clap::Args;
use pointbreak::model::{ActorId, EventId};
use pointbreak::session::{
EventSignatureRecordOptions, EventSignatureRecordResult, record_event_signature,
resolve_writer_actor_id,
};
use serde::Serialize;
use crate::cli::common::resolve_signer;
use crate::cli::json::DiagnosticDocument;
use crate::cli::output;
#[derive(Debug, Args)]
pub(super) struct EndorseArgs {
target: String,
#[arg(long)]
sign_key: Option<String>,
#[arg(long)]
actor: Option<String>,
#[arg(long, default_value = ".")]
repo: PathBuf,
#[arg(long)]
pretty: bool,
#[command(flatten)]
format_args: output::FormatArgs,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct EndorseBody {
event_id: String,
target_event_id: String,
target_event_record_hash: String,
attesting_signer: String,
actor_id: String,
events_created: usize,
events_existing: usize,
}
pub(super) fn run(
args: EndorseArgs,
stdout: &mut dyn Write,
stderr: &mut dyn Write,
) -> Result<(), Box<dyn std::error::Error>> {
let explicit = args.actor.as_deref().map(ActorId::new);
let actor = resolve_writer_actor_id(&args.repo, explicit.as_ref());
let resolution = resolve_signer(&args.repo, &actor, args.sign_key.as_deref());
if let Some(diagnostic) = resolution.diagnostic.as_deref() {
let _ = writeln!(stderr, "{diagnostic}");
}
let signer = resolution.signer.ok_or_else(|| -> Box<dyn std::error::Error> {
"no signing key resolved: an endorsement has no unsigned form (the signature is its content). \
Set --sign-key / SHORE_SIGNING_KEY, or run `shore key init` and `shore key enroll`."
.into()
})?;
let ids = crate::cli::id_resolver::IdResolver::new(&args.repo);
let target = ids.event(&args.target)?;
let result: EventSignatureRecordResult = record_event_signature(
EventSignatureRecordOptions::new(&args.repo, EventId::new(&target), signer)
.with_actor_id(actor.clone()),
)?;
let body = EndorseBody {
event_id: result.event_id.as_str().to_owned(),
target_event_id: result.target_event_id.as_str().to_owned(),
target_event_record_hash: result.target_event_record_hash,
attesting_signer: result.attesting_signer.as_str().to_owned(),
actor_id: actor.as_str().to_owned(),
events_created: result.events_created,
events_existing: result.events_existing,
};
let document = DiagnosticDocument::new("shore.review-endorse", body, Vec::new());
let format = output::resolve_format(
args.format_args.explicit(args.pretty),
output::OutputFormat::Json,
)?;
output::write_document_json_fallback(stdout, format, &document)
}