use bpx_api_types::capital::{Deposit, DepositAddress, Withdrawal};
use owo_colors::OwoColorize;
use tabled::settings::Style;
use tabled::{Table, Tabled};

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

#[derive(Tabled)]
struct DepositRow {
    #[tabled(rename = "ID")]
    id: String,
    #[tabled(rename = "SYMBOL")]
    symbol: String,
    #[tabled(rename = "QTY")]
    quantity: String,
    #[tabled(rename = "STATUS")]
    status: String,
    #[tabled(rename = "SOURCE")]
    source: String,
    #[tabled(rename = "ADDRESS")]
    address: String,
    #[tabled(rename = "CREATED")]
    created_at: String,
}

pub fn print_deposits(deposits: &[Deposit], format: OutputFormat) {
    match format {
        OutputFormat::Json => super::print_json(deposits),
        OutputFormat::Table => {
            if deposits.is_empty() {
                println!("No deposits found.");
                return;
            }
            let rows: Vec<DepositRow> = deposits
                .iter()
                .map(|d| DepositRow {
                    id: d.id.to_string(),
                    symbol: d.symbol.clone(),
                    quantity: d.quantity.to_string(),
                    status: format!("{}", d.status),
                    source: format!("{}", d.source),
                    address: d.to_address.clone().unwrap_or_default(),
                    created_at: d.created_at.format("%Y-%m-%d %H:%M:%S").to_string(),
                })
                .collect();
            let mut table = Table::new(rows);
            table.with(Style::blank());
            println!("{table}");
        }
    }
}

pub fn print_deposit_address(addr: &DepositAddress, chain: &str, format: OutputFormat) {
    match format {
        OutputFormat::Json => super::print_json(addr),
        OutputFormat::Table => {
            let s = Styles::new();
            println!(
                "{} Deposit address for {}: {}",
                "✓".style(s.green),
                chain.style(s.bold),
                addr.address.style(s.cyan)
            );
        }
    }
}

#[derive(Tabled)]
struct WithdrawalRow {
    #[tabled(rename = "ID")]
    id: String,
    #[tabled(rename = "SYMBOL")]
    symbol: String,
    #[tabled(rename = "QTY")]
    quantity: String,
    #[tabled(rename = "FEE")]
    fee: String,
    #[tabled(rename = "STATUS")]
    status: String,
    #[tabled(rename = "CHAIN")]
    chain: String,
    #[tabled(rename = "TO ADDRESS")]
    to_address: String,
    #[tabled(rename = "CREATED")]
    created_at: String,
}

pub fn print_withdrawals(withdrawals: &[Withdrawal], format: OutputFormat) {
    match format {
        OutputFormat::Json => super::print_json(withdrawals),
        OutputFormat::Table => {
            if withdrawals.is_empty() {
                println!("No withdrawals found.");
                return;
            }
            let rows: Vec<WithdrawalRow> = withdrawals
                .iter()
                .map(|w| WithdrawalRow {
                    id: w.id.to_string(),
                    symbol: w.symbol.clone(),
                    quantity: w.quantity.to_string(),
                    fee: w.fee.to_string(),
                    status: format!("{}", w.status),
                    chain: format!("{}", w.blockchain),
                    to_address: w.to_address.clone(),
                    created_at: w.created_at.format("%Y-%m-%d %H:%M:%S").to_string(),
                })
                .collect();
            let mut table = Table::new(rows);
            table.with(Style::blank());
            println!("{table}");
        }
    }
}

pub fn print_withdrawal(withdrawal: &Withdrawal, format: OutputFormat) {
    match format {
        OutputFormat::Json => super::print_json(withdrawal),
        OutputFormat::Table => {
            let s = Styles::new();
            println!(
                "{} Withdrawal submitted: {} {} to {}",
                "✓".style(s.green),
                withdrawal.quantity.style(s.bold),
                withdrawal.symbol.style(s.bold),
                withdrawal.to_address.style(s.cyan)
            );
            println!(
                "  ID: {}  Status: {}  Fee: {}",
                withdrawal.id, withdrawal.status, withdrawal.fee
            );
        }
    }
}
