#![allow(clippy::indexing_slicing)] // ratatui Layout::split indices match constraints
//! Trading cockpit -- positions, executions, account, broker health.

use ratatui::Frame;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::Style;
use ratatui::text::{Line, Span};
use ratatui::widgets::{List, ListItem, Row, Table};

use crate::tui::cockpit::Cockpit;
use crate::tui::state::AppState;
use crate::tui::theme;

pub struct TradingCockpit;

impl Cockpit for TradingCockpit {
    fn name(&self) -> &str {
        "Trading"
    }

    fn render(&self, frame: &mut Frame, area: Rect, state: &AppState) {
        let cols = Layout::default()
            .direction(Direction::Horizontal)
            .constraints([Constraint::Percentage(60), Constraint::Percentage(40)])
            .split(area);

        let left = Layout::default()
            .direction(Direction::Vertical)
            .constraints([Constraint::Percentage(55), Constraint::Percentage(45)])
            .split(cols[0]);

        let right = Layout::default()
            .direction(Direction::Vertical)
            .constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
            .split(cols[1]);

        render_positions(frame, left[0], state);
        render_executions(frame, left[1], state);
        render_account(frame, right[0], state);
        render_broker_health(frame, right[1], state);
    }
}

fn render_positions(frame: &mut Frame, area: Rect, state: &AppState) {
    let header = Row::new(vec!["Symbol", "Qty", "Entry", "Market", "Unrl P&L"])
        .style(theme::header_style());

    let rows: Vec<Row> = state
        .positions
        .iter()
        .map(|p| {
            let pnl_style = if p.unrealized_pnl >= 0.0 {
                theme::status_style(true)
            } else {
                theme::status_style(false)
            };

            Row::new(vec![
                Span::styled(p.symbol.clone(), Style::default().fg(theme::TEXT)),
                Span::styled(
                    format!("{}", p.qty),
                    Style::default().fg(if p.qty >= 0 {
                        theme::SECONDARY
                    } else {
                        theme::WARNING
                    }),
                ),
                Span::styled(format!("{:.2}", p.entry_price), theme::muted_style()),
                Span::styled(
                    format!("{:.2}", p.market_price),
                    Style::default().fg(theme::TEXT),
                ),
                Span::styled(theme::format_usd_signed(p.unrealized_pnl), pnl_style),
            ])
        })
        .collect();

    let table = Table::new(
        rows,
        [
            Constraint::Length(10),
            Constraint::Length(6),
            Constraint::Length(12),
            Constraint::Length(12),
            Constraint::Length(14),
        ],
    )
    .header(header)
    .block(theme::block(" Positions "));

    frame.render_widget(table, area);
}

fn render_executions(frame: &mut Frame, area: Rect, state: &AppState) {
    let header = Row::new(vec!["Time", "Symbol", "Side", "Qty", "Price", "Status"])
        .style(theme::header_style());

    let rows: Vec<Row> = state
        .executions
        .iter()
        .map(|e| {
            let side_style = if e.side == "BUY" {
                Style::default().fg(theme::SUCCESS)
            } else {
                Style::default().fg(theme::ERROR)
            };

            Row::new(vec![
                Span::styled(e.time.clone(), theme::muted_style()),
                Span::styled(e.symbol.clone(), Style::default().fg(theme::TEXT)),
                Span::styled(e.side.clone(), side_style),
                Span::styled(format!("{}", e.qty), Style::default().fg(theme::TEXT)),
                Span::styled(format!("{:.2}", e.price), Style::default().fg(theme::TEXT)),
                Span::styled(e.status.clone(), Style::default().fg(theme::SUCCESS)),
            ])
        })
        .collect();

    let table = Table::new(
        rows,
        [
            Constraint::Length(10),
            Constraint::Length(10),
            Constraint::Length(6),
            Constraint::Length(6),
            Constraint::Length(12),
            Constraint::Length(8),
        ],
    )
    .header(header)
    .block(theme::block(" Recent Executions "));

    frame.render_widget(table, area);
}

fn render_account(frame: &mut Frame, area: Rect, state: &AppState) {
    let pnl_style = if state.account.daily_pnl >= 0.0 {
        theme::status_style(true)
    } else {
        theme::status_style(false)
    };

    let total_pnl_style = if state.account.total_pnl >= 0.0 {
        theme::status_style(true)
    } else {
        theme::status_style(false)
    };

    let items = vec![
        ListItem::new(Line::from(vec![
            Span::styled("Equity      ", theme::muted_style()),
            Span::styled(
                theme::format_usd(state.account.equity),
                Style::default().fg(theme::TEXT),
            ),
        ])),
        ListItem::new(Line::from(vec![
            Span::styled("Cash        ", theme::muted_style()),
            Span::styled(
                theme::format_usd(state.account.cash),
                Style::default().fg(theme::TEXT),
            ),
        ])),
        ListItem::new(Line::from(vec![
            Span::styled("Margin Used ", theme::muted_style()),
            Span::styled(
                theme::format_usd(state.account.margin_used),
                Style::default().fg(theme::WARNING),
            ),
        ])),
        ListItem::new(Line::from(vec![
            Span::styled("Daily P&L   ", theme::muted_style()),
            Span::styled(theme::format_usd_signed(state.account.daily_pnl), pnl_style),
        ])),
        ListItem::new(Line::from(vec![
            Span::styled("Total P&L   ", theme::muted_style()),
            Span::styled(
                theme::format_usd_signed(state.account.total_pnl),
                total_pnl_style,
            ),
        ])),
    ];

    let list = List::new(items).block(theme::block(" Account "));
    frame.render_widget(list, area);
}

fn render_broker_health(frame: &mut Frame, area: Rect, state: &AppState) {
    let header = Row::new(vec!["Time", "Symbol", "Side", "Status", "Fill"])
        .style(theme::header_style());

    let rows: Vec<Row> = state
        .orders
        .iter()
        .rev()
        .take(12)
        .map(|o| {
            let side_style = if o.side == "BUY" {
                Style::default().fg(theme::SUCCESS)
            } else {
                Style::default().fg(theme::ERROR)
            };

            let status_style = match o.status.as_str() {
                "FILLED" => Style::default().fg(theme::SUCCESS),
                "REJECTED" | "CANCELLED" => Style::default().fg(theme::ERROR),
                "PARTIAL" => Style::default().fg(theme::WARNING),
                _ => Style::default().fg(theme::TEXT),
            };

            let fill_pct = if o.qty > 0.0 {
                format!("{:.0}%", (o.filled_qty / o.qty) * 100.0)
            } else {
                "\u{2014}".to_owned()
            };

            Row::new(vec![
                Span::styled(o.time.clone(), theme::muted_style()),
                Span::styled(o.symbol.clone(), Style::default().fg(theme::TEXT)),
                Span::styled(o.side.clone(), side_style),
                Span::styled(o.status.clone(), status_style),
                Span::styled(fill_pct, Style::default().fg(theme::HIGHLIGHT)),
            ])
        })
        .collect();

    let table = Table::new(
        rows,
        [
            Constraint::Length(10),
            Constraint::Length(10),
            Constraint::Length(6),
            Constraint::Length(10),
            Constraint::Length(6),
        ],
    )
    .header(header)
    .block(theme::block(" Orders "));

    frame.render_widget(table, area);
}
