1use std::slice;
7
8use anyhow::{Context, Result};
9use chrono::{DateTime, Utc};
10use clap::{Args, Subcommand, value_parser};
11use ironflow_sdk::IronflowClient;
12use ironflow_sdk::types::{CreateProviderAccountRequest, UpdateProviderAccountRequest};
13
14use crate::confirm::{confirm, resolve_secret_value};
15use crate::output;
16
17#[derive(Debug, Args)]
19pub struct AccountArgs {
20 #[command(subcommand)]
22 pub command: AccountCommands,
23}
24
25#[derive(Debug, Subcommand)]
27pub enum AccountCommands {
28 Add {
30 name: String,
32 #[arg(long, default_value = "claude_subscription")]
34 kind: String,
35 #[arg(long)]
37 display_name: Option<String>,
38 #[arg(long, required = true)]
40 token_stdin: bool,
41 #[arg(long = "tag")]
43 tags: Vec<String>,
44 #[arg(long)]
46 priority: Option<i32>,
47 #[arg(long, value_parser = value_parser!(i32).range(1..))]
49 max_concurrency: Option<i32>,
50 #[arg(long)]
52 alert_threshold: Option<f64>,
53 #[arg(long)]
55 plan: Option<String>,
56 #[arg(long)]
58 expires_at: Option<DateTime<Utc>>,
59 #[arg(long)]
61 disabled: bool,
62 },
63 List {
65 #[arg(long)]
67 kind: Option<String>,
68 },
69 Show {
71 account: String,
73 },
74 Usage {
76 account: String,
78 },
79 Update {
81 account: String,
83 #[arg(long)]
85 display_name: Option<String>,
86 #[arg(long, conflicts_with = "disable")]
88 enable: bool,
89 #[arg(long)]
91 disable: bool,
92 #[arg(long = "tag")]
94 tags: Vec<String>,
95 #[arg(long)]
97 priority: Option<i32>,
98 #[arg(
100 long,
101 conflicts_with = "clear_max_concurrency",
102 value_parser = value_parser!(i32).range(1..)
103 )]
104 max_concurrency: Option<i32>,
105 #[arg(long)]
107 clear_max_concurrency: bool,
108 #[arg(long)]
110 alert_threshold: Option<f64>,
111 #[arg(long)]
113 plan: Option<String>,
114 #[arg(long)]
116 token_stdin: bool,
117 },
118 Remove {
120 account: String,
122 #[arg(long)]
124 yes: bool,
125 },
126 Test {
128 account: String,
130 },
131}
132
133pub async fn execute(client: &IronflowClient, args: &AccountArgs, json_mode: bool) -> Result<()> {
140 match &args.command {
141 AccountCommands::Add {
142 name,
143 kind,
144 display_name,
145 token_stdin: _,
146 tags,
147 priority,
148 max_concurrency,
149 alert_threshold,
150 plan,
151 expires_at,
152 disabled,
153 } => {
154 let token = resolve_secret_value(None, "token")?;
155 let request: CreateProviderAccountRequest = CreateProviderAccountRequest::builder()
156 .name(name.clone())
157 .kind(kind.clone())
158 .token(token)
159 .display_name(display_name.clone())
160 .enabled(Some(!disabled))
161 .tags((!tags.is_empty()).then(|| tags.clone()))
162 .priority(*priority)
163 .max_concurrency(*max_concurrency)
164 .alert_threshold(*alert_threshold)
165 .plan(plan.clone())
166 .expires_at(*expires_at)
167 .try_into()
168 .context("failed to build CreateProviderAccountRequest")?;
169 let response = client.create_provider_account(&request).await?;
170 output::print_output(json_mode, &response, || {
171 output::provider_accounts_table(slice::from_ref(&response.data))
172 })?;
173 }
174 AccountCommands::List { kind } => {
175 let mut response = client.list_provider_accounts().await?;
176 if let Some(kind) = kind {
177 response.data.retain(|a| &a.kind == kind);
178 }
179 output::print_output(json_mode, &response, || {
180 output::provider_accounts_table(&response.data)
181 })?;
182 }
183 AccountCommands::Show { account } => {
184 let response = client.get_provider_account(account).await?;
185 output::print_output(json_mode, &response, || {
186 output::provider_accounts_table(slice::from_ref(&response.data))
187 })?;
188 if !json_mode {
189 println!(
190 "{}",
191 output::provider_account_windows_table(&response.data.windows)
192 );
193 }
194 }
195 AccountCommands::Usage { account } => {
196 let response = client.provider_account_usage(account).await?;
197 output::print_output(json_mode, &response, || {
198 output::provider_account_windows_table(&response.data.windows)
199 })?;
200 }
201 AccountCommands::Update {
202 account,
203 display_name,
204 enable,
205 disable,
206 tags,
207 priority,
208 max_concurrency,
209 clear_max_concurrency,
210 alert_threshold,
211 plan,
212 token_stdin,
213 } => {
214 let token = if *token_stdin {
215 Some(resolve_secret_value(None, "token")?)
216 } else {
217 None
218 };
219 let enabled = match (*enable, *disable) {
220 (true, _) => Some(true),
221 (_, true) => Some(false),
222 _ => None,
223 };
224 let request: UpdateProviderAccountRequest = UpdateProviderAccountRequest::builder()
225 .display_name(display_name.clone())
226 .enabled(enabled)
227 .tags((!tags.is_empty()).then(|| tags.clone()))
228 .priority(*priority)
229 .max_concurrency(*max_concurrency)
230 .alert_threshold(*alert_threshold)
231 .plan(plan.clone())
232 .token(token)
233 .try_into()
234 .context("failed to build UpdateProviderAccountRequest")?;
235 let mut response = client.update_provider_account(account, &request).await?;
236 if *clear_max_concurrency {
237 response = client
238 .clear_provider_account_max_concurrency(account)
239 .await?;
240 }
241 output::print_output(json_mode, &response, || {
242 output::provider_accounts_table(slice::from_ref(&response.data))
243 })?;
244 }
245 AccountCommands::Remove { account, yes } => {
246 confirm(&format!("Delete provider account '{account}'?"), *yes)?;
247 client.delete_provider_account(account).await?;
248 output::report_deletion(json_mode, "provider account", account.clone())?;
249 }
250 AccountCommands::Test { account } => {
251 let response = client.test_provider_account(account).await?;
252 output::print_output(json_mode, &response, || {
253 output::provider_account_windows_table(&response.data.windows)
254 })?;
255 if !json_mode {
256 println!("result: {}", response.data.result);
257 }
258 }
259 }
260 Ok(())
261}