use anyhow::{Context, Result};
use tracing::info;

use crate::client::AdminClient;
use crate::output::{format_json, format_node_detail, format_nodes_table, OutputFormat};

/// List all nodes in the cluster
pub async fn list_nodes(client: &AdminClient, format: OutputFormat) -> Result<()> {
    info!("Fetching node list");
    let status = client.cluster_status().await?;

    match format {
        OutputFormat::Table => {
            println!("\nNODES");
            println!("{}", format_nodes_table(&status.nodes));
        }
        OutputFormat::Json => {
            println!("{}", format_json(&status.nodes)?);
        }
    }

    Ok(())
}

/// Show detailed information about a specific node
pub async fn node_info(client: &AdminClient, node_id: &str, format: OutputFormat) -> Result<()> {
    info!("Fetching info for node: {}", node_id);
    let status = client.cluster_status().await?;
    let shards = client.all_ranges().await?;

    let node = status
        .nodes
        .iter()
        .find(|n| n.id == node_id)
        .context(format!("Node not found: {}", node_id))?;

    match format {
        OutputFormat::Table => {
            println!("{}", format_node_detail(node, &shards));
        }
        OutputFormat::Json => {
            println!("{}", format_json(node)?);
        }
    }

    Ok(())
}

/// Show shards assigned to a specific node
pub async fn node_shards(
    client: &AdminClient,
    node_id: &str,
    leader_only: bool,
    format: OutputFormat,
) -> Result<()> {
    info!("Fetching shards for node: {} (leader_only: {})", node_id, leader_only);
    let status = client.cluster_status().await?;
    let all_shards = client.all_ranges().await?;

    let node = status
        .nodes
        .iter()
        .find(|n| n.id == node_id)
        .context(format!("Node not found: {}", node_id))?;

    // Filter shards for this node
    let node_shards: Vec<_> = all_shards
        .iter()
        .filter(|s| node.shards.contains(&s.range_id))
        .filter(|s| !leader_only || s.leader_node == node_id)
        .cloned()
        .collect();

    match format {
        OutputFormat::Table => {
            if leader_only {
                println!("\nLEADER SHARDS FOR NODE {}", node_id);
            } else {
                println!("\nALL SHARDS FOR NODE {}", node_id);
            }

            if node_shards.is_empty() {
                println!("  (no shards)");
            } else {
                for shard in &node_shards {
                    let role = if shard.leader_node == node_id { "Leader" } else { "Follower" };
                    println!(
                        "  Shard {}: {} - {:.2} MB, {} assertions ({})",
                        shard.range_id,
                        shard.start_key,
                        shard.size_bytes as f64 / 1_048_576.0,
                        shard.assertion_count,
                        role
                    );
                }
            }
        }
        OutputFormat::Json => {
            println!("{}", format_json(&node_shards)?);
        }
    }

    Ok(())
}
