use anyhow::{Context, Result};
use colored::Colorize;
use dialoguer::{Select, Input, Confirm};
use std::path::PathBuf;
use crate::config::FireCloudConfig;
pub async fn run(data_dir: PathBuf) -> Result<()> {
println!("\n{}", "⚙️ Modify Storage Provider Settings".bold().cyan());
println!("{}", "─".repeat(50).dimmed());
let config_path = data_dir.join("config.toml");
let mut config = FireCloudConfig::load(&config_path)
.unwrap_or_default();
let current_quota = config.storage_quota;
if let Some(quota) = current_quota {
println!("\n{} Current Status: {}", "✓".green(), "Storage Provider Active".bold());
println!(" Current Quota: {}", format_size(quota).yellow());
} else {
println!("\n{} Current Status: {}", "ℹ".blue(), "Not a Storage Provider".dimmed());
}
let options = if current_quota.is_some() {
vec![
"Increase Storage Quota",
"Decrease Storage Quota",
"Disable Storage Sharing",
"Cancel",
]
} else {
vec![
"Enable Storage Sharing",
"Cancel",
]
};
let selection = Select::new()
.with_prompt("What would you like to do?")
.items(&options)
.default(0)
.interact_opt()?;
match selection {
Some(idx) => {
match options[idx] {
"Enable Storage Sharing" => {
enable_storage_sharing(&mut config, &config_path).await?;
}
"Increase Storage Quota" => {
modify_quota(&mut config, &config_path, true).await?;
}
"Decrease Storage Quota" => {
modify_quota(&mut config, &config_path, false).await?;
}
"Disable Storage Sharing" => {
disable_storage_sharing(&mut config, &config_path).await?;
}
"Cancel" => {
println!("\n{} Operation cancelled", "✓".yellow());
}
_ => {}
}
}
None => {
println!("\n{} Operation cancelled", "✓".yellow());
}
}
Ok(())
}
async fn enable_storage_sharing(config: &mut FireCloudConfig, config_path: &PathBuf) -> Result<()> {
println!("\n{}", "Enable Storage Sharing".bold());
let quota_str: String = Input::new()
.with_prompt("How much storage would you like to provide? (e.g., 10GB, 500MB)")
.default("10GB".to_string())
.interact_text()?;
let quota_bytes = parse_size("a_str)
.context("Invalid storage size format")?;
config.storage_quota = Some(quota_bytes);
config.save(config_path)
.context("Failed to save configuration")?;
println!("\n{} Storage sharing enabled!", "✓".green());
println!(" Quota: {}", format_size(quota_bytes).yellow());
println!("\n{} Next: View your dashboard with {}",
"ℹ".blue(),
"firecloud usage".cyan());
Ok(())
}
async fn modify_quota(config: &mut FireCloudConfig, config_path: &PathBuf, increase: bool) -> Result<()> {
let current = config.storage_quota.unwrap_or(0);
let action = if increase { "Increase" } else { "Decrease" };
println!("\n{} Storage Quota", action.bold());
println!(" Current: {}", format_size(current).dimmed());
let new_quota_str: String = Input::new()
.with_prompt("New quota (e.g., 20GB, 1TB)")
.default(format_size(current))
.interact_text()?;
let new_quota = parse_size(&new_quota_str)
.context("Invalid storage size format")?;
if !increase && new_quota < current {
let confirm = Confirm::new()
.with_prompt(format!(
"Warning: Decreasing quota may affect stored chunks. Continue?"
))
.default(false)
.interact()?;
if !confirm {
println!("\n{} Operation cancelled", "✓".yellow());
return Ok(());
}
}
config.storage_quota = Some(new_quota);
config.save(config_path)
.context("Failed to save configuration")?;
println!("\n{} Quota updated!", "✓".green());
println!(" Old: {}", format_size(current).dimmed());
println!(" New: {}", format_size(new_quota).yellow());
Ok(())
}
async fn disable_storage_sharing(config: &mut FireCloudConfig, config_path: &PathBuf) -> Result<()> {
println!("\n{}", "Disable Storage Sharing".bold().yellow());
let confirm = Confirm::new()
.with_prompt("Are you sure? This will stop accepting new chunks.")
.default(false)
.interact()?;
if !confirm {
println!("\n{} Operation cancelled", "✓".yellow());
return Ok(());
}
config.storage_quota = None;
config.save(config_path)
.context("Failed to save configuration")?;
println!("\n{} Storage sharing disabled", "✓".green());
println!(" Existing chunks will remain until manually deleted");
println!("\n{} To re-enable later, run: {}",
"ℹ".blue(),
"firecloud mod".cyan());
Ok(())
}
fn parse_size(s: &str) -> Result<u64> {
let s = s.trim().to_uppercase();
let (num_str, multiplier) = if s.ends_with("TB") {
(&s[..s.len()-2], 1_000_000_000_000u64)
} else if s.ends_with("GB") {
(&s[..s.len()-2], 1_000_000_000u64)
} else if s.ends_with("MB") {
(&s[..s.len()-2], 1_000_000u64)
} else if s.ends_with("KB") {
(&s[..s.len()-2], 1_000u64)
} else if s.ends_with('B') {
(&s[..s.len()-1], 1u64)
} else {
(s.as_str(), 1u64)
};
let num: f64 = num_str.trim().parse()
.context("Invalid number in size specification")?;
Ok((num * multiplier as f64) as u64)
}
fn format_size(bytes: u64) -> String {
const KB: u64 = 1_000;
const MB: u64 = 1_000_000;
const GB: u64 = 1_000_000_000;
const TB: u64 = 1_000_000_000_000;
if bytes >= TB {
format!("{:.2} TB", bytes as f64 / TB as f64)
} else if bytes >= GB {
format!("{:.2} GB", bytes as f64 / GB as f64)
} else if bytes >= MB {
format!("{:.2} MB", bytes as f64 / MB as f64)
} else if bytes >= KB {
format!("{:.2} KB", bytes as f64 / KB as f64)
} else {
format!("{} B", bytes)
}
}