//! Node commands.

use anyhow::Result;

use crate::client::RpcClient;
use crate::output::{self, OutputFormat};

/// Get node info.
pub async fn info(client: &RpcClient, format: OutputFormat) -> Result<()> {
    let info = client.get_info().await?;

    match format {
        OutputFormat::Json => {
            output::print_value(&info, format);
        }
        OutputFormat::Text => {
            output::print_header("Node Information");
            output::print_kv("Version", &info.version);
            output::print_kv("Protocol", &info.protocol_version.to_string());
            output::print_kv("Network", &info.network);
            output::print_kv("Peers", &info.peer_count.to_string());
            output::print_kv("Synced", if info.synced { "Yes" } else { "No" });
            output::print_kv("Block Count", &info.block_count.to_string());
            output::print_kv("Blue Score", &info.blue_score.to_string());
            output::print_kv("Mempool Size", &info.mempool_size.to_string());
        }
    }

    Ok(())
}

/// Get node version.
pub async fn version(client: &RpcClient, format: OutputFormat) -> Result<()> {
    let version = client.get_version().await?;

    match format {
        OutputFormat::Json => {
            output::print_value(&version, format);
        }
        OutputFormat::Text => {
            println!("{} v{}", version.name, version.version);
        }
    }

    Ok(())
}

/// Get sync status.
pub async fn sync_status(client: &RpcClient, format: OutputFormat) -> Result<()> {
    let info = client.get_info().await?;

    match format {
        OutputFormat::Json => {
            let status = serde_json::json!({
                "synced": info.synced,
                "block_count": info.block_count,
                "blue_score": info.blue_score,
            });
            println!("{}", serde_json::to_string_pretty(&status)?);
        }
        OutputFormat::Text => {
            if info.synced {
                output::print_success("Node is synced");
                output::print_kv("Block Count", &info.block_count.to_string());
                output::print_kv("Blue Score", &info.blue_score.to_string());
            } else {
                output::print_warning("Node is syncing...");
                output::print_kv("Current Block", &info.block_count.to_string());
            }
        }
    }

    Ok(())
}

/// Get peer info.
pub async fn peers(client: &RpcClient, format: OutputFormat) -> Result<()> {
    let peers = client.get_peer_info().await?;

    match format {
        OutputFormat::Json => {
            output::print_value(&peers, format);
        }
        OutputFormat::Text => {
            if peers.is_empty() {
                output::print_warning("No peers connected");
                return Ok(());
            }

            output::print_header(&format!("Connected Peers ({})", peers.len()));

            let headers = vec!["ID", "Address", "Direction", "Latency", "User Agent"];
            let rows: Vec<Vec<String>> = peers
                .iter()
                .map(|p| {
                    vec![
                        output::format_hash(&p.id),
                        p.address.clone(),
                        if p.is_inbound { "in" } else { "out" }.to_string(),
                        format!("{}ms", p.latency_ms),
                        p.user_agent.clone(),
                    ]
                })
                .collect();

            output::print_table(headers, rows);
        }
    }

    Ok(())
}
