use std::collections::HashMap;

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

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

#[derive(Tabled)]
struct StrategyRow {
    #[tabled(rename = "NAME")]
    name: String,
    #[tabled(rename = "SYMBOL")]
    symbol: String,
    #[tabled(rename = "SIDE")]
    side: String,
    #[tabled(rename = "SIZE")]
    size: String,
    #[tabled(rename = "STOP LOSS")]
    stop_loss: String,
    #[tabled(rename = "TAKE PROFIT")]
    take_profit: String,
    #[tabled(rename = "AUTO LEND")]
    auto_lend: String,
}

pub fn print_strategies(strategies: &HashMap<String, StrategyConfig>, format: OutputFormat) {
    match format {
        OutputFormat::Json => super::print_json(strategies),
        OutputFormat::Table => {
            if strategies.is_empty() {
                println!("No strategies configured.");
                return;
            }
            let s = Styles::new();
            let mut entries: Vec<(&String, &StrategyConfig)> = strategies.iter().collect();
            entries.sort_by_key(|(name, _)| (*name).clone());

            let rows: Vec<StrategyRow> = entries
                .iter()
                .map(|(name, strat)| {
                    let side_display = if strat.side == "buy" {
                        format!("{}", "BUY".style(s.green))
                    } else {
                        format!("{}", "SELL".style(s.red))
                    };
                    StrategyRow {
                        name: (*name).clone(),
                        symbol: strat.symbol.clone(),
                        side: side_display,
                        size: strat.size.clone(),
                        stop_loss: strat.stop_loss.as_deref().unwrap_or("-").to_string(),
                        take_profit: strat.take_profit.as_deref().unwrap_or("-").to_string(),
                        auto_lend: if strat.auto_lend {
                            "Yes".to_string()
                        } else {
                            "No".to_string()
                        },
                    }
                })
                .collect();

            let mut table = Table::new(rows);
            table.with(Style::blank());
            println!("{table}");
        }
    }
}

pub fn print_strategy_created(name: &str, strategy: &StrategyConfig, format: OutputFormat) {
    match format {
        OutputFormat::Json => {
            super::print_json(&serde_json::json!({
                "status": "created",
                "name": name,
                "strategy": {
                    "symbol": strategy.symbol,
                    "side": strategy.side,
                    "size": strategy.size,
                    "stop_loss": strategy.stop_loss,
                    "take_profit": strategy.take_profit,
                    "auto_lend": strategy.auto_lend,
                }
            }));
        }
        OutputFormat::Table => {
            let s = Styles::new();
            println!(
                "  {} Strategy '{}' created",
                "OK".style(s.green),
                name.style(s.bold)
            );
            println!(
                "     {} {} {} size={}",
                strategy.symbol,
                strategy.side.to_uppercase(),
                strategy.size,
                if strategy.auto_lend { " auto-lend" } else { "" }
            );
        }
    }
}

pub fn print_strategy_dry_run(
    name: &str,
    strategy: &StrategyConfig,
    payload: &ExecuteOrderPayload,
    size: Decimal,
    format: OutputFormat,
) {
    match format {
        OutputFormat::Json => {
            super::print_json(&serde_json::json!({
                "dry_run": true,
                "strategy": name,
                "payload": {
                    "symbol": payload.symbol,
                    "side": format!("{:?}", payload.side),
                    "order_type": format!("{:?}", payload.order_type),
                    "quantity": size.to_string(),
                    "stop_loss": strategy.stop_loss,
                    "take_profit": strategy.take_profit,
                    "auto_lend": strategy.auto_lend,
                }
            }));
        }
        OutputFormat::Table => {
            let s = Styles::new();
            println!();
            println!(
                "  {} Strategy '{}' (dry run)",
                "DRY RUN".style(s.yellow),
                name.style(s.bold)
            );
            println!("  Symbol:      {}", payload.symbol);
            println!(
                "  Side:        {}",
                if strategy.side == "buy" {
                    format!("{}", "BUY".style(s.green))
                } else {
                    format!("{}", "SELL".style(s.red))
                }
            );
            println!("  Type:        Market");
            println!("  Size:        {size}");
            if let Some(sl) = &strategy.stop_loss {
                println!("  Stop Loss:   {sl}");
            }
            if let Some(tp) = &strategy.take_profit {
                println!("  Take Profit: {tp}");
            }
            println!(
                "  Auto Lend:   {}",
                if strategy.auto_lend { "Yes" } else { "No" }
            );
            println!();
            println!(
                "  {}",
                "No order was placed. Remove --dry-run to execute.".style(s.dim)
            );
            println!();
        }
    }
}

pub fn print_strategy_executed(name: &str, order: &Order, format: OutputFormat) {
    match format {
        OutputFormat::Json => {
            super::print_json(&serde_json::json!({
                "status": "executed",
                "strategy": name,
                "order": order,
            }));
        }
        OutputFormat::Table => {
            let s = Styles::new();
            println!();
            println!(
                "  {} Strategy '{}' executed",
                "OK".style(s.green),
                name.style(s.bold)
            );
            match order {
                Order::Limit(l) => {
                    println!("  Order ID: {}", l.id);
                    println!("  Status:   {}", l.status);
                }
                Order::Market(m) => {
                    println!("  Order ID: {}", m.id);
                    println!("  Status:   {}", m.status);
                }
            }
            println!();
        }
    }
}

pub fn print_strategy_deleted(name: &str, format: OutputFormat) {
    match format {
        OutputFormat::Json => {
            super::print_json(&serde_json::json!({
                "status": "deleted",
                "name": name,
            }));
        }
        OutputFormat::Table => {
            let s = Styles::new();
            println!(
                "  {} Strategy '{}' deleted",
                "OK".style(s.green),
                name.style(s.bold)
            );
        }
    }
}
