//! CLI utilities.
#![allow(dead_code)]

use std::io::{self, Write};

/// Prints a banner.
pub fn print_banner() {
    println!(
        r#"
  ███████╗██╗   ██╗███╗   ██╗ ██████╗ ██████╗
  ██╔════╝╚██╗ ██╔╝████╗  ██║██╔═══██╗██╔══██╗
  ███████╗ ╚████╔╝ ██╔██╗ ██║██║   ██║██████╔╝
  ╚════██║  ╚██╔╝  ██║╚██╗██║██║   ██║██╔══██╗
  ███████║   ██║   ██║ ╚████║╚██████╔╝██║  ██║
  ╚══════╝   ╚═╝   ╚═╝  ╚═══╝ ╚═════╝ ╚═╝  ╚═╝

  Synor Blockchain Node v{}
  BlockDAG with GHOSTDAG Consensus
"#,
        env!("CARGO_PKG_VERSION")
    );
}

/// Prompts for confirmation.
pub fn confirm(prompt: &str) -> bool {
    print!("{} [y/N]: ", prompt);
    io::stdout().flush().unwrap();

    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();

    matches!(input.trim().to_lowercase().as_str(), "y" | "yes")
}

/// Formats a hash for display.
pub fn format_hash(hash: &[u8]) -> String {
    if hash.len() >= 8 {
        format!(
            "{}...{}",
            hex::encode(&hash[..4]),
            hex::encode(&hash[hash.len() - 4..])
        )
    } else {
        hex::encode(hash)
    }
}

/// Formats bytes as human-readable size.
pub fn format_size(bytes: u64) -> String {
    const KB: u64 = 1024;
    const MB: u64 = KB * 1024;
    const GB: u64 = MB * 1024;
    const TB: u64 = GB * 1024;

    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)
    }
}

/// Formats a hashrate.
pub fn format_hashrate(hps: f64) -> String {
    const K: f64 = 1000.0;
    const M: f64 = K * 1000.0;
    const G: f64 = M * 1000.0;
    const T: f64 = G * 1000.0;
    const P: f64 = T * 1000.0;

    if hps >= P {
        format!("{:.2} PH/s", hps / P)
    } else if hps >= T {
        format!("{:.2} TH/s", hps / T)
    } else if hps >= G {
        format!("{:.2} GH/s", hps / G)
    } else if hps >= M {
        format!("{:.2} MH/s", hps / M)
    } else if hps >= K {
        format!("{:.2} KH/s", hps / K)
    } else {
        format!("{:.2} H/s", hps)
    }
}

/// Formats duration in seconds.
pub fn format_duration(seconds: u64) -> String {
    if seconds < 60 {
        format!("{}s", seconds)
    } else if seconds < 3600 {
        format!("{}m {}s", seconds / 60, seconds % 60)
    } else if seconds < 86400 {
        format!(
            "{}h {}m {}s",
            seconds / 3600,
            (seconds % 3600) / 60,
            seconds % 60
        )
    } else {
        format!(
            "{}d {}h {}m",
            seconds / 86400,
            (seconds % 86400) / 3600,
            (seconds % 3600) / 60
        )
    }
}

/// Formats SYNOR amount.
pub fn format_synor(sompi: u64) -> String {
    let synor = sompi as f64 / 100_000_000.0;
    format!("{:.8} SYNOR", synor)
}

/// Parses SYNOR amount.
pub fn parse_synor(s: &str) -> anyhow::Result<u64> {
    let s = s.trim().to_uppercase();
    let s = s.strip_suffix("SYNOR").unwrap_or(&s).trim();

    let synor: f64 = s.parse()?;
    let sompi = (synor * 100_000_000.0) as u64;

    Ok(sompi)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_format_size() {
        assert_eq!(format_size(500), "500 B");
        assert_eq!(format_size(1024), "1.00 KB");
        assert_eq!(format_size(1024 * 1024), "1.00 MB");
        assert_eq!(format_size(1024 * 1024 * 1024), "1.00 GB");
    }

    #[test]
    fn test_format_hashrate() {
        assert_eq!(format_hashrate(500.0), "500.00 H/s");
        assert_eq!(format_hashrate(1500.0), "1.50 KH/s");
        assert_eq!(format_hashrate(1_500_000.0), "1.50 MH/s");
    }

    #[test]
    fn test_format_synor() {
        assert_eq!(format_synor(100_000_000), "1.00000000 SYNOR");
        assert_eq!(format_synor(50_000_000), "0.50000000 SYNOR");
    }

    #[test]
    fn test_parse_synor() {
        assert_eq!(parse_synor("1").unwrap(), 100_000_000);
        assert_eq!(parse_synor("1.5 SYNOR").unwrap(), 150_000_000);
        assert_eq!(parse_synor("0.5").unwrap(), 50_000_000);
    }
}
