use bpx_api_types::order::{BatchOrderResponse, Order};
use owo_colors::OwoColorize;
use tabled::settings::Style;
use tabled::{Table, Tabled};

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

#[derive(Tabled)]
struct OrderRow {
    #[tabled(rename = "ID")]
    id: String,
    #[tabled(rename = "SYMBOL")]
    symbol: String,
    #[tabled(rename = "SIDE")]
    side: String,
    #[tabled(rename = "TYPE")]
    order_type: String,
    #[tabled(rename = "TIF")]
    tif: String,
    #[tabled(rename = "PRICE")]
    price: String,
    #[tabled(rename = "QTY")]
    quantity: String,
    #[tabled(rename = "FILLED")]
    filled: String,
    #[tabled(rename = "STATUS")]
    status: String,
}

fn order_to_row(o: &Order, s: &Styles) -> OrderRow {
    match o {
        Order::Limit(l) => {
            let side_display = if l.side == bpx_api_types::order::Side::Bid {
                format!("{}", "BUY".style(s.green))
            } else {
                format!("{}", "SELL".style(s.red))
            };
            OrderRow {
                id: l.id.clone(),
                symbol: l.symbol.clone(),
                side: side_display,
                order_type: "Limit".to_string(),
                tif: super::display_tif(&l.time_in_force).to_string(),
                price: l.price.to_string(),
                quantity: l.quantity.to_string(),
                filled: l.executed_quantity.to_string(),
                status: format!("{}", l.status),
            }
        }
        Order::Market(m) => {
            let side_display = if m.side == bpx_api_types::order::Side::Bid {
                format!("{}", "BUY".style(s.green))
            } else {
                format!("{}", "SELL".style(s.red))
            };
            OrderRow {
                id: m.id.clone(),
                symbol: m.symbol.clone(),
                side: side_display,
                order_type: "Market".to_string(),
                tif: super::display_tif(&m.time_in_force).to_string(),
                price: "Market".to_string(),
                quantity: m
                    .quantity
                    .map(|q| q.to_string())
                    .unwrap_or_else(|| "-".to_string()),
                filled: m.executed_quantity.to_string(),
                status: format!("{}", m.status),
            }
        }
    }
}

pub fn print_order(order: &Order, format: OutputFormat) {
    match format {
        OutputFormat::Json => super::print_json(order),
        OutputFormat::Table => {
            let s = Styles::new();
            let rows = vec![order_to_row(order, &s)];
            let mut table = Table::new(rows);
            table.with(Style::blank());
            println!("{table}");
        }
    }
}

pub fn print_orders(orders: &[Order], format: OutputFormat) {
    match format {
        OutputFormat::Json => super::print_json(orders),
        OutputFormat::Table => {
            if orders.is_empty() {
                println!("No orders found.");
                return;
            }
            let s = Styles::new();
            let rows: Vec<OrderRow> = orders.iter().map(|o| order_to_row(o, &s)).collect();
            let mut table = Table::new(rows);
            table.with(Style::blank());
            println!("{table}");
        }
    }
}

pub fn print_cancel_success(symbol: &str, order_id: &str, format: OutputFormat) {
    match format {
        OutputFormat::Json => {
            super::print_json(&serde_json::json!({
                "status": "cancelled",
                "symbol": symbol,
                "order_id": order_id,
            }));
        }
        OutputFormat::Table => {
            let s = Styles::new();
            println!(
                "{} Cancelled order {} on {}",
                "✓".style(s.green),
                order_id.style(s.bold),
                symbol.style(s.bold)
            );
        }
    }
}

pub fn print_cancel_all_success(symbol: &str, format: OutputFormat) {
    match format {
        OutputFormat::Json => {
            super::print_json(&serde_json::json!({
                "status": "cancelled_all",
                "symbol": symbol,
            }));
        }
        OutputFormat::Table => {
            let s = Styles::new();
            println!(
                "{} Cancelled all orders on {}",
                "✓".style(s.green),
                symbol.style(s.bold)
            );
        }
    }
}

pub fn print_batch_results(responses: &[BatchOrderResponse], format: OutputFormat) {
    match format {
        OutputFormat::Json => super::print_json(responses),
        OutputFormat::Table => {
            if responses.is_empty() {
                println!("No results.");
                return;
            }
            let s = Styles::new();
            let success_count = responses
                .iter()
                .filter(|r| matches!(r, BatchOrderResponse::Order(_)))
                .count();
            let error_count = responses.len() - success_count;
            if responses.len() > 1 {
                println!(
                    "  {} succeeded, {} failed ({} total)",
                    success_count.to_string().style(s.green),
                    error_count
                        .to_string()
                        .style(if error_count > 0 { s.red } else { s.dim }),
                    responses.len()
                );
                println!();
            }
            for (i, resp) in responses.iter().enumerate() {
                match resp {
                    BatchOrderResponse::Order(order) => {
                        let rows = vec![order_to_row(order, &s)];
                        let mut table = Table::new(rows);
                        table.with(Style::blank());
                        println!("{table}");
                    }
                    BatchOrderResponse::Error(err) => {
                        eprintln!(
                            "{} Order {}: {} ({})",
                            "✗".style(s.red),
                            i + 1,
                            err.message,
                            err.code
                        );
                    }
                }
            }
        }
    }
}
