use clap::Args;
use mk_codec::KeyCard;
use serde_json::json;
use crate::cmd::{
classify_code_variant, derive_stub_from_md1, parse_derivation_path, parse_fingerprint,
parse_stub_hex, parse_xpub,
};
use crate::error::{CliError, Result};
#[derive(Args, Debug)]
pub struct EncodeArgs {
#[arg(long)]
pub xpub: String,
#[arg(long)]
pub origin_fingerprint: Option<String>,
#[arg(long)]
pub origin_path: String,
#[arg(long)]
pub policy_id_stub: Vec<String>,
#[arg(long)]
pub from_md1: Vec<String>,
#[arg(long)]
pub privacy_preserving: bool,
#[arg(long)]
pub force_chunked: bool,
#[arg(long)]
pub force_long_code: bool,
#[arg(long)]
pub json: bool,
}
pub fn run(args: EncodeArgs) -> Result<()> {
if args.privacy_preserving && args.origin_fingerprint.is_some() {
return Err(CliError::UsageError(
"--privacy-preserving and --origin-fingerprint are mutually exclusive".into(),
));
}
let mut stubs: Vec<[u8; 4]> = Vec::new();
for s in &args.policy_id_stub {
stubs.push(parse_stub_hex(s)?);
}
for md1 in &args.from_md1 {
stubs.push(derive_stub_from_md1(md1)?);
}
if stubs.is_empty() {
return Err(CliError::UsageError(
"at least one of --policy-id-stub or --from-md1 is required".into(),
));
}
let fingerprint = match (&args.origin_fingerprint, args.privacy_preserving) {
(Some(s), false) => Some(parse_fingerprint(s)?),
(None, true) => None,
(None, false) => None,
(Some(_), true) => unreachable!("guarded above"),
};
let path = parse_derivation_path(&args.origin_path)?;
let xpub = parse_xpub(&args.xpub)?;
let card = KeyCard::new(stubs, fingerprint, path, xpub);
let strings = mk_codec::encode(&card)?;
if args.json {
emit_json(&strings)?;
} else {
for s in &strings {
println!("{s}");
}
}
Ok(())
}
fn emit_json(strings: &[String]) -> Result<()> {
let variant = strings
.first()
.map(|s| classify_code_variant(s))
.unwrap_or("regular");
let envelope = json!({
"schema_version": 1,
"mk1_strings": strings,
"chunk_count": strings.len(),
"code_variant": variant,
});
let s = serde_json::to_string(&envelope)
.map_err(|e| CliError::UsageError(format!("json serialization: {e}")))?;
println!("{s}");
Ok(())
}