#![allow(clippy::indexing_slicing)] // ratatui Layout::split indices match constraints
//! Risk cockpit -- kill switches, drawdown, circuit breakers, position limits.

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

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

pub struct RiskCockpit;

impl Cockpit for RiskCockpit {
    fn name(&self) -> &str {
        "Risk"
    }

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

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

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

        render_kill_switches(frame, left[0], state);
        render_drawdown(frame, left[1], state);
        render_circuit_breakers(frame, right[0], state);
        render_position_limits(frame, right[1], state);
    }
}

fn render_kill_switches(frame: &mut Frame, area: Rect, state: &AppState) {
    let switches = [
        ("Global      ", state.risk.global_kill_switch),
        ("Portfolio   ", state.risk.portfolio_kill_switch),
        ("Strategy    ", state.risk.strategy_kill_switch),
        ("Instrument  ", state.risk.instrument_kill_switch),
    ];

    let items: Vec<ListItem> = switches
        .iter()
        .map(|(name, active)| {
            let (label, style) = match active {
                Some(true) => (
                    "TRIPPED",
                    Style::default().fg(theme::ERROR).add_modifier(Modifier::BOLD),
                ),
                Some(false) => ("SAFE", Style::default().fg(theme::SUCCESS)),
                None => ("N/A", theme::muted_style()),
            };

            ListItem::new(Line::from(vec![
                Span::styled(*name, theme::muted_style()),
                Span::styled(label, style),
            ]))
        })
        .collect();

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

fn render_drawdown(frame: &mut Frame, area: Rect, state: &AppState) {
    let block = theme::block(" Drawdown Monitor ");
    let inner = block.inner(area);
    frame.render_widget(block, area);

    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Length(2),
            Constraint::Length(2),
            Constraint::Length(2),
            Constraint::Min(0),
        ])
        .split(inner);

    // Current drawdown gauge
    let dd_pct = state.risk.current_drawdown_pct / 100.0;
    let dd_color = if state.risk.current_drawdown_pct > 5.0 {
        theme::ERROR
    } else if state.risk.current_drawdown_pct > 3.0 {
        theme::WARNING
    } else {
        theme::SUCCESS
    };
    let dd_gauge = Gauge::default()
        .gauge_style(Style::default().fg(dd_color))
        .label(format!(
            "Current DD  {:.1}%",
            state.risk.current_drawdown_pct,
        ))
        .ratio(dd_pct.clamp(0.0, 1.0));
    frame.render_widget(dd_gauge, chunks[0]);

    // Max drawdown
    let max_dd_pct = state.risk.max_drawdown_pct / 100.0;
    let max_dd_gauge = Gauge::default()
        .gauge_style(Style::default().fg(theme::WARNING))
        .label(format!("Max DD      {:.1}%", state.risk.max_drawdown_pct))
        .ratio(max_dd_pct.clamp(0.0, 1.0));
    frame.render_widget(max_dd_gauge, chunks[1]);

    // High water mark
    let hwm_items = vec![ListItem::new(Line::from(vec![
        Span::styled("High Water  ", theme::muted_style()),
        Span::styled(
            theme::format_usd(state.risk.high_water_mark),
            Style::default().fg(theme::HIGHLIGHT),
        ),
    ]))];
    let hwm = List::new(hwm_items);
    frame.render_widget(hwm, chunks[2]);
}

fn render_circuit_breakers(frame: &mut Frame, area: Rect, state: &AppState) {
    let header = Row::new(vec!["Breaker", "Threshold", "Current", "Status"])
        .style(theme::header_style());

    let rows: Vec<Row> = state
        .risk
        .circuit_breakers
        .iter()
        .map(|cb| {
            let status_text = if cb.tripped { "TRIPPED" } else { "OK" };
            let status_style = if cb.tripped {
                Style::default()
                    .fg(theme::ERROR)
                    .add_modifier(Modifier::BOLD)
            } else {
                Style::default().fg(theme::SUCCESS)
            };

            let threshold_text = cb
                .threshold
                .map_or_else(|| "\u{2014}".to_owned(), |v| format!("{v:.1}"));
            let current_text = cb
                .current
                .map_or_else(|| "\u{2014}".to_owned(), |v| format!("{v:.1}"));

            Row::new(vec![
                Span::styled(cb.name.clone(), Style::default().fg(theme::TEXT)),
                Span::styled(threshold_text, theme::muted_style()),
                Span::styled(current_text, Style::default().fg(theme::TEXT)),
                Span::styled((*status_text).to_owned(), status_style),
            ])
        })
        .collect();

    let table = Table::new(
        rows,
        [
            Constraint::Length(18),
            Constraint::Length(12),
            Constraint::Length(10),
            Constraint::Length(10),
        ],
    )
    .header(header)
    .block(theme::block(" Circuit Breakers "));

    frame.render_widget(table, area);
}

fn render_position_limits(frame: &mut Frame, area: Rect, state: &AppState) {
    // Show risk alerts when available, fall back to position limits.
    if !state.risk_alerts.is_empty() {
        render_risk_alerts(frame, area, state);
        return;
    }

    // When no data is available at all, show a placeholder.
    if state.risk.position_limits.is_empty() {
        let items = vec![ListItem::new(Line::from(Span::styled(
            "No position limit data",
            theme::muted_style(),
        )))];
        let list = List::new(items).block(theme::block(" Position Limits "));
        frame.render_widget(list, area);
        return;
    }

    let header = Row::new(vec!["Symbol", "Max", "Current", "Usage"])
        .style(theme::header_style());

    let rows: Vec<Row> = state
        .risk
        .position_limits
        .iter()
        .map(|pl| {
            let usage_pct = if pl.max_qty > 0 {
                (pl.current_qty as f64 / pl.max_qty as f64) * 100.0
            } else {
                0.0
            };

            let usage_style = if usage_pct > 80.0 {
                Style::default().fg(theme::ERROR)
            } else if usage_pct > 50.0 {
                Style::default().fg(theme::WARNING)
            } else {
                Style::default().fg(theme::SUCCESS)
            };

            Row::new(vec![
                Span::styled(pl.symbol.clone(), Style::default().fg(theme::TEXT)),
                Span::styled(format!("{}", pl.max_qty), theme::muted_style()),
                Span::styled(
                    format!("{}", pl.current_qty),
                    Style::default().fg(theme::TEXT),
                ),
                Span::styled(format!("{:.0}%", usage_pct), usage_style),
            ])
        })
        .collect();

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

    frame.render_widget(table, area);
}

fn render_risk_alerts(frame: &mut Frame, area: Rect, state: &AppState) {
    let header = Row::new(vec!["Time", "Sev", "Type", "Message"])
        .style(theme::header_style());

    let rows: Vec<Row> = state
        .risk_alerts
        .iter()
        .rev()
        .take(10)
        .map(|a| {
            let sev_style = match a.severity.as_str() {
                "EMRG" | "CRIT" => Style::default()
                    .fg(theme::ERROR)
                    .add_modifier(Modifier::BOLD),
                "WARN" => Style::default().fg(theme::WARNING),
                _ => Style::default().fg(theme::TEXT),
            };

            Row::new(vec![
                Span::styled(a.time.clone(), theme::muted_style()),
                Span::styled(a.severity.clone(), sev_style),
                Span::styled(a.alert_type.clone(), Style::default().fg(theme::HIGHLIGHT)),
                Span::styled(
                    truncate_str(&a.message, 30),
                    Style::default().fg(theme::TEXT),
                ),
            ])
        })
        .collect();

    let table = Table::new(
        rows,
        [
            Constraint::Length(10),
            Constraint::Length(5),
            Constraint::Length(10),
            Constraint::Min(10),
        ],
    )
    .header(header)
    .block(theme::block(" Risk Alerts "));

    frame.render_widget(table, area);
}

fn truncate_str(s: &str, max: usize) -> String {
    if s.len() <= max {
        s.to_owned()
    } else {
        let mut t = s.chars().take(max.saturating_sub(1)).collect::<String>();
        t.push('\u{2026}');
        t
    }
}
