#![allow(clippy::indexing_slicing)] // ratatui Layout::split indices match constraints
//! Data cockpit -- live feeds, cache stats, pipeline status.

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 DataCockpit;

impl Cockpit for DataCockpit {
    fn name(&self) -> &str {
        "Data"
    }

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

        render_feeds(frame, rows[0], state);

        let bottom = Layout::default()
            .direction(Direction::Horizontal)
            .constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
            .split(rows[1]);

        render_cache_stats(frame, bottom[0], state);
        render_pipeline(frame, bottom[1], state);
    }
}

fn render_feeds(frame: &mut Frame, area: Rect, state: &AppState) {
    let header = Row::new(vec!["Symbol", "Records/s", "Latency", "Status"])
        .style(theme::header_style());

    let rows: Vec<Row> = state
        .data_feeds
        .iter()
        .map(|f| {
            let latency_style = if f.latency_us > 100 {
                Style::default().fg(theme::ERROR)
            } else if f.latency_us > 50 {
                Style::default().fg(theme::WARNING)
            } else {
                Style::default().fg(theme::SUCCESS)
            };

            let status_style = match f.status.as_str() {
                "LIVE" | "OK" | "ACTIVE" | "RUNNING" => Style::default().fg(theme::SUCCESS),
                "PAUSED" | "IDLE" => Style::default().fg(theme::WARNING),
                _ => Style::default().fg(theme::ERROR),
            };

            let rps_text = if f.records_per_sec == 0 {
                format!("{:>8}", "\u{2014}")
            } else {
                format!("{:>8}", format_number(f.records_per_sec))
            };

            let latency_text = if f.latency_us == 0 {
                format!("{:>5}", "\u{2014}")
            } else {
                format!("{:>4}us", f.latency_us)
            };

            Row::new(vec![
                Span::styled(f.symbol.clone(), Style::default().fg(theme::TEXT)),
                Span::styled(rps_text, Style::default().fg(theme::HIGHLIGHT)),
                Span::styled(latency_text, latency_style),
                Span::styled(f.status.clone(), status_style),
            ])
        })
        .collect();

    let table = Table::new(
        rows,
        [
            Constraint::Length(10),
            Constraint::Length(12),
            Constraint::Length(10),
            Constraint::Length(10),
        ],
    )
    .header(header)
    .block(theme::block(" Active Data Feeds "));

    frame.render_widget(table, area);
}

fn render_cache_stats(frame: &mut Frame, area: Rect, state: &AppState) {
    let items = vec![
        ListItem::new(Line::from(vec![
            Span::styled("Total Records  ", theme::muted_style()),
            Span::styled(
                format_number(state.data_cache.total_records),
                Style::default().fg(theme::TEXT),
            ),
        ])),
        ListItem::new(Line::from(vec![
            Span::styled("Hit Rate       ", theme::muted_style()),
            Span::styled(
                format!("{:.1}%", state.data_cache.cache_hit_rate),
                Style::default().fg(theme::HIGHLIGHT),
            ),
        ])),
        ListItem::new(Line::from(vec![
            Span::styled("Disk Usage     ", theme::muted_style()),
            Span::styled(
                format!("{:.1} GB", state.data_cache.disk_usage_gb),
                Style::default().fg(theme::TEXT),
            ),
        ])),
        ListItem::new(Line::from(vec![
            Span::styled("Date Range     ", theme::muted_style()),
            Span::styled(
                format!("{} -- {}", state.data_cache.oldest_date, state.data_cache.newest_date),
                theme::muted_style(),
            ),
        ])),
    ];

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

fn render_pipeline(frame: &mut Frame, area: Rect, _state: &AppState) {
    let items = vec![ListItem::new(Line::from(Span::styled(
        "Pipeline monitoring not connected",
        theme::muted_style(),
    )))];

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

/// Format a large number with thousand separators (e.g. 12_480 -> "12,480").
fn format_number(n: u64) -> String {
    let s = n.to_string();
    let bytes = s.as_bytes();
    let len = bytes.len();
    #[allow(clippy::integer_division)]
    let cap = len + len / 3;
    let mut result = String::with_capacity(cap);
    for (i, &b) in bytes.iter().enumerate() {
        if i > 0 && (len - i) % 3 == 0 {
            result.push(',');
        }
        result.push(b as char);
    }
    result
}
