use bpx_api_types::futures::FuturePosition;
use owo_colors::OwoColorize;
use tabled::settings::Style;
use tabled::{Table, Tabled};

use crate::output::OutputFormat;
use crate::style::Styles;

#[derive(Tabled)]
struct PositionRow {
    #[tabled(rename = "SYMBOL")]
    symbol: String,
    #[tabled(rename = "NET QTY")]
    net_quantity: String,
    #[tabled(rename = "ENTRY PRICE")]
    entry_price: String,
    #[tabled(rename = "BREAK EVEN")]
    break_even: String,
    #[tabled(rename = "MARK PRICE")]
    mark_price: String,
    #[tabled(rename = "LIQ PRICE")]
    liq_price: String,
    #[tabled(rename = "UNREALIZED PNL")]
    pnl_unrealized: String,
    #[tabled(rename = "REALIZED PNL")]
    pnl_realized: String,
}

pub fn print_positions(positions: &[FuturePosition], format: OutputFormat) {
    match format {
        OutputFormat::Json => super::print_json(positions),
        OutputFormat::Table => {
            if positions.is_empty() {
                println!("No open positions.");
                return;
            }
            let s = Styles::new();
            let rows: Vec<PositionRow> = positions
                .iter()
                .map(|p| {
                    let pnl_unreal = format_pnl(&p.pnl_unrealized, &s);
                    let pnl_real = format_pnl(&p.pnl_realized, &s);
                    PositionRow {
                        symbol: p.symbol.clone(),
                        net_quantity: p.net_quantity.clone(),
                        entry_price: p.entry_price.clone(),
                        break_even: p.break_even_price.clone(),
                        mark_price: p.mark_price.clone(),
                        liq_price: p.est_liquidation_price.clone(),
                        pnl_unrealized: pnl_unreal,
                        pnl_realized: pnl_real,
                    }
                })
                .collect();
            let mut table = Table::new(rows);
            table.with(Style::blank());
            println!("{table}");
        }
    }
}

pub fn print_close_success(symbol: &str, quantity: &str, side: &str, format: OutputFormat) {
    match format {
        OutputFormat::Json => {
            super::print_json(&serde_json::json!({
                "status": "closed",
                "symbol": symbol,
                "quantity": quantity,
                "side": side,
            }));
        }
        OutputFormat::Table => {
            let s = Styles::new();
            println!(
                "{} Closed position: {} {} {} (market, reduce-only)",
                "\u{2713}".style(s.green),
                side.style(s.bold),
                quantity.style(s.bold),
                symbol.style(s.bold),
            );
        }
    }
}

fn format_pnl(value: &str, s: &Styles) -> String {
    if value.starts_with('-') {
        format!("{}", value.style(s.red))
    } else if value.parse::<f64>().is_ok_and(|v| v == 0.0) {
        value.to_string()
    } else {
        format!("{}", value.style(s.green))
    }
}
