use std::{collections::HashMap, str::FromStr};

use color_eyre::eyre::{Result, eyre};
use v_exchanges::core::{Exchange, ExchangeName, Instrument};
use v_utils::trades::Usd;

pub mod config;

pub fn initialize_exchanges(config: &config::AppConfig) -> Result<Vec<Box<dyn Exchange>>> {
	let mut exchanges: Vec<Box<dyn Exchange>> = Vec::new();
	for (name, exchange_config) in &config.exchanges {
		let exchange_name = ExchangeName::from_str(name)?;
		let mut exchange = exchange_name.init_client();
		exchange.auth(exchange_config.api_pubkey.clone(), exchange_config.api_secret.clone());
		exchange.set_max_tries(3);
		exchange.set_recv_window(std::time::Duration::from_secs(15));

		// special case: KuCoin requires a passphrase
		if exchange_name == ExchangeName::Kucoin {
			let passphrase = exchange_config.passphrase.clone().ok_or_else(|| eyre!("Kucoin exchange requires passphrase in config"))?;
			exchange.update_default_option(v_exchanges::kucoin::KucoinOption::Passphrase(passphrase));
		}

		exchanges.push(exchange);
	}
	Ok(exchanges)
}

pub async fn collect_balances(exchanges: &[Box<dyn Exchange>]) -> Result<HashMap<String, Usd>> {
	let mut balances = HashMap::new();
	for exchange in exchanges {
		let balance = exchange.balances(Instrument::Perp, None).await.unwrap();
		let name = exchange.name().to_string();
		tracing::debug!("Per-Exchange balances: {name}: {balance:?}");
		balances.insert(name, balance.total);
	}
	Ok(balances)
}

pub async fn get_total_balance(config: &config::AppConfig, balances: &HashMap<String, Usd>) -> Result<Usd> {
	let mut total_balance = Usd(0.);
	for balance in balances.values() {
		total_balance += *balance;
	}

	// Add other balances if configured
	if let Some(other) = config.other_balances {
		total_balance = Usd(*total_balance + other);
	}

	Ok(total_balance)
}
