//! cg-ohlc: Fetch OHLCV candlestick data from CoinGecko
//!
//! Downloads OHLCV (Open, High, Low, Close, Volume) data for technical analysis.

mod cli;
mod error;
mod models;

use cg_common::{CoinGeckoClient, CoinGeckoClientBuilder, JsonWriter};
use clap::Parser;
use cli::{Args, OutputFormat};
use error::Result;
use models::OhlcCandle;
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();

    // Validate args
    args.validate()?;

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

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

    // Fetch OHLC data
    let candles = fetch_ohlc(&client, &coin_id, &args).await?;

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

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

    Ok(())
}

async fn fetch_ohlc(
    client: &CoinGeckoClient,
    coin_id: &str,
    args: &Args,
) -> Result<Vec<OhlcCandle>> {
    let endpoint = format!(
        "/coins/{}/ohlc?vs_currency={}&days={}",
        coin_id, args.vs_currency, args.days
    );

    let response = client.get(&endpoint).await?;

    // CoinGecko returns: [[timestamp, open, high, low, close], ...]
    let raw: Vec<Vec<f64>> = serde_json::from_str(&response)?;

    let candles: Vec<OhlcCandle> = raw
        .into_iter()
        .filter_map(|c| {
            if c.len() >= 5 {
                Some(OhlcCandle {
                    timestamp: c[0] as i64,
                    open: c[1],
                    high: c[2],
                    low: c[3],
                    close: c[4],
                })
            } else {
                None
            }
        })
        .collect();

    Ok(candles)
}
