firecloud-cli 0.2.0

Command-line interface for FireCloud P2P messaging and file sharing
// UI utilities for beautiful CLI output
use colored::*;
use comfy_table::{Table, Cell, Attribute, Color as TableColor, ContentArrangement};
use indicatif::{ProgressBar, ProgressStyle};
use std::time::Duration;

/// Print a fancy header
pub fn print_header(title: &str) {
    let width = 60;
    let border = "═".repeat(width);
    
    println!("\n{}", border.bright_blue().bold());
    println!("{}", format!(" đŸ”Ĩ {}  ", title).bright_blue().bold());
    println!("{}", border.bright_blue().bold());
}

/// Print a section box
pub fn print_box(title: &str, content: &[&str]) {
    println!("\n{}", format!("┌─ {} {}", title, "─".repeat(60 - title.len() - 3)).bright_blue());
    for line in content {
        println!("{} {}", "│".bright_blue(), line);
    }
    println!("{}", format!("└{}", "─".repeat(60)).bright_blue());
}

/// Print a success message
pub fn success(msg: &str) {
    println!("{} {}", "✅".green(), msg.green().bold());
}

/// Print an info message
pub fn info(msg: &str) {
    println!("{} {}", "â„šī¸ ".bright_blue(), msg.bright_blue());
}

/// Print a warning message
pub fn warning(msg: &str) {
    println!("{} {}", "âš ī¸ ".yellow(), msg.yellow());
}

/// Print an error message
pub fn error(msg: &str) {
    println!("{} {}", "❌".red(), msg.red().bold());
}

/// Print a novelty highlight
pub fn novelty(number: u8, title: &str, content: &[&str]) {
    let header = format!("NOVELTY #{}: {}", number, title);
    println!("\n{}", format!("┌─ {} {}", header, "─".repeat(std::cmp::max(60, header.len() + 4) - header.len() - 3)).bright_magenta().bold());
    for line in content {
        println!("{} {}", "│".bright_magenta(), line);
    }
    println!("{}", format!("└{}", "─".repeat(std::cmp::max(60, header.len() + 4))).bright_magenta());
}

/// Create a progress bar for file operations
pub fn create_progress_bar(total: u64, message: &str) -> ProgressBar {
    let pb = ProgressBar::new(total);
    pb.set_style(
        ProgressStyle::default_bar()
            .template("{msg}\n{spinner:.green} [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})")
            .unwrap()
            .progress_chars("█▓▒░ "),
    );
    pb.set_message(message.to_string());
    pb
}

/// Create a spinner for indeterminate operations
pub fn create_spinner(message: &str) -> ProgressBar {
    let pb = ProgressBar::new_spinner();
    pb.set_style(
        ProgressStyle::default_spinner()
            .template("{spinner:.green} {msg}")
            .unwrap()
            .tick_strings(&["⠋", "⠙", "â š", "â ¸", "â ŧ", "â ´", "â Ļ", "â §", "⠇", "⠏"]),
    );
    pb.set_message(message.to_string());
    pb.enable_steady_tick(Duration::from_millis(80));
    pb
}

/// Print a comparison table
pub fn print_comparison_table(rows: Vec<(&str, &str, &str, &str)>) {
    let mut table = Table::new();
    table
        .set_content_arrangement(ContentArrangement::Dynamic)
        .set_header(vec![
            Cell::new("File").fg(TableColor::Cyan).add_attribute(Attribute::Bold),
            Cell::new("Strategy").fg(TableColor::Cyan).add_attribute(Attribute::Bold),
            Cell::new("Time").fg(TableColor::Cyan).add_attribute(Attribute::Bold),
            Cell::new("Size").fg(TableColor::Cyan).add_attribute(Attribute::Bold),
        ]);
    
    for (file, strategy, time, size) in rows {
        table.add_row(vec![
            Cell::new(file),
            Cell::new(strategy).fg(TableColor::Green),
            Cell::new(time),
            Cell::new(size),
        ]);
    }
    
    println!("\n{}", table);
}

/// Show network topology
pub fn print_network_topology(local_peers: &[(String, u32)], regional_peers: &[(String, u32)], global_peers: &[(String, u32)]) {
    println!("\n{}", "🌐 FireCloud Network Topology (Live)".bright_cyan().bold());
    println!();
    println!("{}", "YOU (local-node)".bright_white().bold());
    println!(" │");
    
    if !local_peers.is_empty() {
        println!(" {}", "├─ LOCAL (mDNS) ─────────────────".bright_green());
        for (i, (name, latency)) in local_peers.iter().enumerate() {
            let prefix = if i == local_peers.len() - 1 { "└─" } else { "├─" };
            println!(" │   {} đŸ’ģ {} ({}ms)", prefix.bright_green(), name, latency.to_string().bright_green());
        }
        println!(" │");
    }
    
    if !regional_peers.is_empty() {
        println!(" {}", "├─ REGIONAL (DHT) ───────────────".yellow());
        for (i, (name, latency)) in regional_peers.iter().enumerate() {
            let prefix = if i == regional_peers.len() - 1 { "└─" } else { "├─" };
            println!(" │   {} đŸ–Ĩī¸  {} ({}ms)", prefix.yellow(), name, latency.to_string().yellow());
        }
        println!(" │");
    }
    
    if !global_peers.is_empty() {
        println!(" {}", "└─ GLOBAL (DHT) ─────────────────".red());
        for (i, (name, latency)) in global_peers.iter().enumerate() {
            let prefix = if i == global_peers.len() - 1 { "└─" } else { "├─" };
            println!("     {} 🌍 {} ({}ms)", prefix.red(), name, latency.to_string().red());
        }
    }
}

/// Show file piece distribution
pub fn print_piece_distribution(file_name: &str, file_size: &str, local: usize, regional: usize, global: usize) {
    println!("\n{}", format!("File: {} ({})", file_name, file_size).bright_white().bold());
    println!("{}", "Pieces distributed:".bright_white());
    
    let local_pieces = "đŸŸĸ".repeat(local);
    let regional_pieces = "🟡".repeat(regional);
    let global_pieces = "🔴".repeat(global);
    
    println!("  {} Local ({} pieces - fast reads)", local_pieces, local);
    println!("  {} Regional ({} pieces - medium)", regional_pieces, regional);
    println!("  {} Global ({} piece - durability)", global_pieces, global);
    
    println!("\n{}", "This is NOVELTY #3 in action! ⚡".bright_magenta().bold());
}

/// Print benchmark results
pub fn print_benchmark(name: &str, our_time: f64, their_time: f64, speedup: f64) {
    println!("\n{}", format!("📊 Benchmark: {}", name).bright_cyan().bold());
    println!();
    
    let our_bar = "█".repeat((our_time / their_time * 40.0) as usize);
    let their_bar = "█".repeat(40);
    
    println!("{}", "Dropbox:".bright_white());
    println!("{} {:.1}s", their_bar.red(), their_time);
    println!();
    println!("{}", "FireCloud:".bright_white());
    println!("{} {:.1}s", our_bar.green(), our_time);
    println!();
    println!("{} {}", "🚀 FireCloud is".green().bold(), format!("{:.1}x FASTER!", speedup).green().bold());
}

/// Print status dashboard
pub fn print_status(network_mode: &str, local_peers: usize, dht_peers: usize, storage_used: f64, storage_total: f64, shares_active: usize, shares_pending: usize) {
    println!("\n┌────────────────────────────────────────┐");
    println!("│ {} {}                  │", "đŸ”Ĩ".bright_yellow(), "FireCloud Status".bright_white().bold());
    println!("├────────────────────────────────────────┤");
    println!("│ {}: {}    │", "Network Mode".bright_cyan(), network_mode.bright_white());
    println!("│ {} {} peers discovered   │", "  â€ĸ".bright_green(), local_peers.to_string().bright_green());
    println!("│ {} {} peers in routing │", "  â€ĸ".bright_blue(), dht_peers.to_string().bright_blue());
    
    let storage_pct = (storage_used / storage_total * 100.0) as usize;
    let storage_bar = "█".repeat(storage_pct / 4);
    let storage_empty = "░".repeat(25 - storage_pct / 4);
    
    println!("│ {}: {:.1} GB / {:.1} GB ({}%)    │", "Storage".bright_cyan(), storage_used, storage_total, storage_pct);
    println!("│   [{}{}]            │", storage_bar.bright_green(), storage_empty.bright_black());
    println!("│ {}: {} active | {} pending      │", "Shares".bright_cyan(), shares_active.to_string().bright_white(), shares_pending.to_string().bright_yellow());
    println!("└────────────────────────────────────────┘");
}