1use clap::Args;
2use serde_json::Value;
3
4use crate::client::BackpacClient;
5use crate::errors::CairnError;
6
7use super::{output_json, Cli};
8
9#[derive(Args, Debug)]
10pub struct ReceiveArgs {
11 #[arg(long, required = true)]
13 pub poi_id: String,
14
15 #[arg(long)]
17 pub from: Option<String>,
18
19 #[arg(long)]
21 pub recipient: Option<String>,
22
23 #[arg(long)]
25 pub expect_value: Option<String>,
26
27 #[arg(long)]
29 pub require_finalized: bool,
30}
31
32impl ReceiveArgs {
33 pub async fn execute(&self, cli: &Cli) -> Result<(), CairnError> {
34 let client = BackpacClient::new(cli.jwt.as_deref(), cli.api_url.as_deref(), cli.worker_url.as_deref());
35
36 let mut query_parts = vec![];
38 if let Some(f) = &self.from {
39 query_parts.push(format!("from={}", f));
40 }
41 if let Some(r) = &self.recipient {
42 query_parts.push(format!("recipient={}", r));
43 }
44
45 let path = if query_parts.is_empty() {
46 format!("/v1/pois/{}", self.poi_id)
47 } else {
48 format!("/v1/pois/{}?{}", self.poi_id, query_parts.join("&"))
49 };
50
51 let poi: Value = client.get(&path).await?;
53
54 if let Some(expected_val) = &self.expect_value {
56 let actual_val = poi
57 .get("metadata")
58 .and_then(|m| m.get("amount").or_else(|| poi.get("amount"))) .and_then(|a| {
60 if a.is_number() {
61 Some(a.to_string())
62 } else {
63 a.as_str().map(|s| s.to_string())
64 }
65 });
66
67 if let Some(actual) = actual_val {
68 if actual != *expected_val {
69 return Err(CairnError::ValueMismatch(format!(
70 "Expected {}, got {}",
71 expected_val, actual
72 )));
73 }
74 } else {
75 return Err(CairnError::ValueMismatch(format!(
76 "PoI does not contain an amount to verify against expected value {}",
77 expected_val
78 )));
79 }
80 }
81
82 let status = poi.get("status").and_then(|s| s.as_str()).unwrap_or("UNKNOWN");
84 if self.require_finalized && status != "SETTLED" && status != "FINALIZED" {
85 return Err(CairnError::NotFinalized(format!(
86 "Intent status is {}, but FINALIZED is required",
87 status
88 )));
89 }
90
91 let verified_payload = serde_json::json!({
95 "poi_id": self.poi_id,
96 "status": status,
97 "verified": true,
98 "message": "Payment intent received and verified",
99 "poi": poi,
100 });
101
102 output_json(&verified_payload, &cli.output);
103 Ok(())
104 }
105}