//! cg-coin: Fetch cryptocurrency data from CoinGecko
//!
//! Downloads comprehensive coin data including market data, developer metrics,
//! and social sentiment.

mod cli;
mod error;
mod models;

use cg_common::{CoinGeckoClient, CoinGeckoClientBuilder, JsonWriter};
use clap::Parser;
use cli::{Args, OutputFormat};
use error::Result;
use models::CoinResponse;
use tracing::info;

fn main() -> Result<()> {
    // Reset SIGPIPE to default behavior (terminate silently) to avoid panic on broken pipe
    #[cfg(unix)]
    unsafe {
        libc::signal(libc::SIGPIPE, libc::SIG_DFL);
    }

    tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap()
        .block_on(async_main())
}

async fn async_main() -> Result<()> {
    let args = Args::parse();

    // Initialize tracing based on verbose flag
    let log_level = if args.verbose {
        tracing::Level::DEBUG
    } else {
        tracing::Level::WARN
    };
    tracing_subscriber::fmt()
        .with_writer(std::io::stderr)
        .with_env_filter(
            tracing_subscriber::EnvFilter::from_default_env().add_directive(log_level.into()),
        )
        .init();

    // Handle --list command
    if args.list {
        print_symbols();
        return Ok(());
    }

    // Validate args
    args.validate()?;

    // Resolve coin ID
    let coin_id = args.resolve_coin_id()?;
    info!("Fetching data for: {}", coin_id);

    // Build client
    let client = CoinGeckoClientBuilder::new().with_rate_limit(25).build()?;

    // Fetch coin data
    let coin = fetch_coin(&client, &coin_id, &args).await?;

    // Output
    let pretty = args.format == OutputFormat::Json;
    let writer = JsonWriter::new(args.output.clone(), pretty);
    writer.write(&coin)?;

    if let Some(path) = &args.output {
        eprintln!("Wrote data to: {:?}", path);
    }

    Ok(())
}

async fn fetch_coin(client: &CoinGeckoClient, coin_id: &str, args: &Args) -> Result<CoinResponse> {
    let endpoint = format!(
        "/coins/{}?localization=false&tickers={}&market_data=true&community_data={}&developer_data={}&sparkline=false",
        coin_id,
        args.tickers,
        args.community,
        args.developer
    );

    let response = client.get(&endpoint).await?;
    let coin: CoinResponse = serde_json::from_str(&response)?;
    Ok(coin)
}

fn print_symbols() {
    println!("Supported symbols (ticker -> CoinGecko ID):\n");

    let mut symbols: Vec<_> = cg_common::SYMBOL_MAP.iter().collect();
    symbols.sort_by_key(|(k, _)| *k);

    for (symbol, id) in symbols {
        println!("  {:8} -> {}", symbol, id);
    }

    println!("\nYou can also use CoinGecko IDs directly (e.g., 'bitcoin', 'ethereum')");
}
